2 * PROJECT: ReactOS Storage Stack
3 * LICENSE: DDK - see license.txt in the root dir
4 * FILE: drivers/storage/cdrom/cdrom.c
5 * PURPOSE: CDROM driver
6 * PROGRAMMERS: Based on a source code sample from Microsoft NT4 DDK
15 #include <include/class2.h>
21 #define CDB12GENERIC_LENGTH 12
23 typedef struct _XA_CONTEXT
{
26 // Pointer to the device object.
29 PDEVICE_OBJECT DeviceObject
;
32 // Pointer to the original request when
33 // a mode select must be sent.
39 // Pointer to the mode select srb.
42 PSCSI_REQUEST_BLOCK Srb
;
43 } XA_CONTEXT
, *PXA_CONTEXT
;
45 typedef struct _ERROR_RECOVERY_DATA
{
46 MODE_PARAMETER_HEADER Header
;
47 MODE_PARAMETER_BLOCK BlockDescriptor
;
48 MODE_READ_RECOVERY_PAGE ReadRecoveryPage
;
49 } ERROR_RECOVERY_DATA
, *PERROR_RECOVERY_DATA
;
51 typedef struct _ERROR_RECOVERY_DATA10
{
52 MODE_PARAMETER_HEADER10 Header10
;
53 MODE_PARAMETER_BLOCK BlockDescriptor10
;
54 MODE_READ_RECOVERY_PAGE ReadRecoveryPage10
;
55 } ERROR_RECOVERY_DATA10
, *PERROR_RECOVERY_DATA10
;
58 // CdRom specific addition to device extension.
61 typedef struct _CDROM_DATA
{
64 // Indicates whether an audio play operation
65 // is currently being performed.
71 // Indicates whether the blocksize used for user data
78 // Indicates whether 6 or 10 byte mode sense/select
85 // Storage for the error recovery page. This is used
86 // as an easy method to switch block sizes.
90 ERROR_RECOVERY_DATA u1
;
91 ERROR_RECOVERY_DATA10 u2
;
96 // Pointer to the original irp for the raw read.
102 // Used to protect accesses to the RawAccess flag.
105 KSPIN_LOCK FormSpinLock
;
108 // Even if media change support is requested, there are some devices
109 // that are not supported. This flag will indicate that such a device
110 // is present when it is FALSE.
113 BOOLEAN MediaChangeSupported
;
116 // The media change event is being supported. The media change timer
117 // should be running whenever this is true.
123 // The timer value to support media change events. This is a countdown
124 // value used to determine when to poll the device for a media change.
125 // The max value for the timer is 255 seconds.
128 UCHAR MediaChangeCountDown
;
132 // Second timer to keep track of how long the media change IRP has been
133 // in use. If this value exceeds the timeout (#defined) then we should
134 // print out a message to the user and set the MediaChangeIrpLost flag
137 SHORT MediaChangeIrpTimeInUse
;
140 // Set by CdRomTickHandler when we determine that the media change irp has
144 BOOLEAN MediaChangeIrpLost
;
147 UCHAR PadReserve
; // use this for new flags.
150 // An IRP is allocated and kept for the duration that media change
151 // detection is in effect. If this is NULL and MediaChange is TRUE,
152 // the detection is in progress. This should always be NULL when
153 // MediaChange is FALSE.
159 // The timer work list is a collection of IRPS that are prepared for
160 // submission, but need to allow some time to pass before they are
164 LIST_ENTRY TimerIrpList
;
165 KSPIN_LOCK TimerIrpSpinLock
;
167 } CDROM_DATA
, *PCDROM_DATA
;
169 #define DEVICE_EXTENSION_SIZE sizeof(DEVICE_EXTENSION) + sizeof(CDROM_DATA)
170 #define SCSI_CDROM_TIMEOUT 10
171 #define SCSI_CHANGER_BONUS_TIMEOUT 10
172 #define HITACHI_MODE_DATA_SIZE 12
173 #define MODE_DATA_SIZE 64
174 #define RAW_SECTOR_SIZE 2352
175 #define COOKED_SECTOR_SIZE 2048
176 #define MEDIA_CHANGE_DEFAULT_TIME 4
177 #define CDROM_SRB_LIST_SIZE 4
183 // Used to detect the loss of the autorun irp. The driver prints out a message
184 // (debug level 0) if this timeout ever occurs
186 #define MEDIA_CHANGE_TIMEOUT_TIME 300
190 #define PLAY_ACTIVE(DeviceExtension) (((PCDROM_DATA)(DeviceExtension + 1))->PlayActive)
192 #define MSF_TO_LBA(Minutes,Seconds,Frames) \
193 (ULONG)((60 * 75 * (Minutes)) + (75 * (Seconds)) + ((Frames) - 150))
195 #define LBA_TO_MSF(Lba,Minutes,Seconds,Frames) \
197 (Minutes) = (UCHAR)(Lba / (60 * 75)); \
198 (Seconds) = (UCHAR)((Lba % (60 * 75)) / 75); \
199 (Frames) = (UCHAR)((Lba % (60 * 75)) % 75); \
202 #define DEC_TO_BCD(x) (((x / 10) << 4) + (x % 10))
205 // Define flags for XA, CDDA, and Mode Select/Sense
208 #define XA_USE_6_BYTE 0x01
209 #define XA_USE_10_BYTE 0x02
210 #define XA_USE_READ_CD 0x04
211 #define XA_NOT_SUPPORTED 0x08
213 #define PLEXTOR_CDDA 0x10
214 #define NEC_CDDA 0x20
217 // Sector types for READ_CD
221 #define CD_DA_SECTOR 1
222 #define YELLOW_MODE1_SECTOR 2
223 #define YELLOW_MODE2_SECTOR 3
224 #define FORM2_MODE1_SECTOR 4
225 #define FORM2_MODE2_SECTOR 5
229 #ifdef ExAllocatePool
230 #undef ExAllocatePool
232 #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'CscS')
238 IN PDRIVER_OBJECT DriverObject
,
239 IN PUNICODE_STRING RegistryPath
244 ScsiCdRomFindDevices(
245 IN PDRIVER_OBJECT DriverObject
,
246 IN PUNICODE_STRING RegistryPath
,
247 IN PCLASS_INIT_DATA InitializationData
,
248 IN PDEVICE_OBJECT PortDeviceObject
,
255 IN PDEVICE_OBJECT DeviceObject
,
261 ScsiCdRomReadVerification(
262 IN PDEVICE_OBJECT DeviceObject
,
269 IN PDEVICE_OBJECT DeviceObject
,
271 IN PIRP OriginalRequest
277 IN PDEVICE_OBJECT DeviceObject
,
281 IO_COMPLETION_ROUTINE CdRomDeviceControlCompletion
;
284 CdRomDeviceControlCompletion(
285 IN PDEVICE_OBJECT DeviceObject
,
290 IO_COMPLETION_ROUTINE CdRomSetVolumeIntermediateCompletion
;
293 CdRomSetVolumeIntermediateCompletion(
294 IN PDEVICE_OBJECT DeviceObject
,
299 IO_COMPLETION_ROUTINE CdRomSwitchModeCompletion
;
302 CdRomSwitchModeCompletion(
303 IN PDEVICE_OBJECT DeviceObject
,
308 IO_COMPLETION_ROUTINE CdRomXACompletion
;
312 IN PDEVICE_OBJECT DeviceObject
,
317 IO_COMPLETION_ROUTINE CdRomClassIoctlCompletion
;
320 CdRomClassIoctlCompletion(
321 IN PDEVICE_OBJECT DeviceObject
,
329 IN PDEVICE_OBJECT DeviceObject
,
336 IN PDEVICE_OBJECT DeviceObject
,
342 CdRomCheckRegistryForMediaChangeValue(
343 IN PUNICODE_STRING RegistryPath
,
344 IN ULONG DeviceNumber
350 IN PDEVICE_EXTENSION DeviceExtension
,
351 IN PIRP IrpToComplete
,
352 IN OPTIONAL PKEVENT IoctlEvent
357 CreateCdRomDeviceObject(
358 IN PDRIVER_OBJECT DriverObject
,
359 IN PDEVICE_OBJECT PortDeviceObject
,
361 IN PULONG DeviceCount
,
362 PIO_SCSI_CAPABILITIES PortCapabilities
,
363 IN PSCSI_INQUIRY_DATA LunInfo
,
364 IN PCLASS_INIT_DATA InitializationData
,
365 IN PUNICODE_STRING RegistryPath
371 PDEVICE_OBJECT DeviceObject
,
372 PINQUIRYDATA InquiryData
,
373 PIO_SCSI_CAPABILITIES PortCapabilities
379 IN PDEVICE_OBJECT DeviceObject
385 PDEVICE_OBJECT DeviceObject
,
386 PSCSI_REQUEST_BLOCK Srb
,
391 IO_COMPLETION_ROUTINE ToshibaProcessErrorCompletion
;
395 PDEVICE_OBJECT DeviceObject
,
396 PSCSI_REQUEST_BLOCK Srb
,
403 IsThisAnAtapiChanger(
404 IN PDEVICE_OBJECT DeviceObject
,
405 OUT PULONG DiscsPresent
411 IN PDEVICE_OBJECT DeviceObject
,
418 IsThisAMultiLunDevice(
419 IN PDEVICE_OBJECT DeviceObject
,
420 IN PDEVICE_OBJECT PortDeviceObject
425 CdRomCreateNamedEvent(
426 IN PDEVICE_EXTENSION DeviceExtension
,
427 IN ULONG DeviceNumber
434 IN UNICODE_STRING ScsiUnicodeString
[],
435 OUT PUCHAR IntermediateController
440 #pragma alloc_text(PAGE, DriverEntry)
441 #pragma alloc_text(PAGE, ScsiCdRomFindDevices)
442 #pragma alloc_text(PAGE, CreateCdRomDeviceObject)
443 #pragma alloc_text(PAGE, ScanForSpecial)
444 //#pragma alloc_text(PAGE, CdRomDeviceControl)
445 #pragma alloc_text(PAGE, HitachProcessError)
446 #pragma alloc_text(PAGE, CdRomIsPlayActive)
447 #pragma alloc_text(PAGE, ScsiCdRomReadVerification)
448 #pragma alloc_text(INIT, CdRomCheckRegistryForMediaChangeValue)
449 #pragma alloc_text(INIT, IsThisAnAtapiChanger)
450 #pragma alloc_text(INIT, IsThisASanyo)
451 #pragma alloc_text(INIT, IsThisAMultiLunDevice)
452 #pragma alloc_text(INIT, CdRomCreateNamedEvent)
454 #pragma alloc_text(PAGE, FindScsiAdapter)
463 IN PDRIVER_OBJECT DriverObject
,
464 IN PUNICODE_STRING RegistryPath
471 This routine initializes the cdrom class driver.
475 DriverObject - Pointer to driver object created by system.
477 RegistryPath - Pointer to the name of the services node for this driver.
481 The function value is the final status from the initialization operation.
486 CLASS_INIT_DATA InitializationData
;
489 return STATUS_NO_SUCH_DEVICE
;
496 RtlZeroMemory (&InitializationData
, sizeof(CLASS_INIT_DATA
));
502 InitializationData
.InitializationDataSize
= sizeof(CLASS_INIT_DATA
);
503 InitializationData
.DeviceExtensionSize
= DEVICE_EXTENSION_SIZE
;
505 InitializationData
.DeviceType
= FILE_DEVICE_CD_ROM
;
506 InitializationData
.DeviceCharacteristics
= FILE_REMOVABLE_MEDIA
| FILE_READ_ONLY_DEVICE
;
512 InitializationData
.ClassReadWriteVerification
= ScsiCdRomReadVerification
;
513 InitializationData
.ClassDeviceControl
= CdRomDeviceControl
;
514 InitializationData
.ClassFindDevices
= ScsiCdRomFindDevices
;
515 InitializationData
.ClassShutdownFlush
= NULL
;
516 InitializationData
.ClassCreateClose
= NULL
;
517 InitializationData
.ClassStartIo
= ScsiCdRomStartIo
;
520 // Call the class init routine
523 return ScsiClassInitialize( DriverObject
, RegistryPath
, &InitializationData
);
525 } // end DriverEntry()
529 ScsiCdRomFindDevices(
530 IN PDRIVER_OBJECT DriverObject
,
531 IN PUNICODE_STRING RegistryPath
,
532 IN PCLASS_INIT_DATA InitializationData
,
533 IN PDEVICE_OBJECT PortDeviceObject
,
541 Connect to SCSI port driver. Get adapter capabilities and
542 SCSI bus configuration information. Search inquiry data
543 for CDROM devices to process.
547 DriverObject - CDROM class driver object.
548 PortDeviceObject - SCSI port driver device object.
549 PortNumber - The system ordinal for this scsi adapter.
553 TRUE if CDROM device present on this SCSI adapter.
558 PIO_SCSI_CAPABILITIES portCapabilities
;
561 PSCSI_INQUIRY_DATA lunInfo
;
562 PSCSI_ADAPTER_BUS_INFO adapterInfo
;
563 PINQUIRYDATA inquiryData
;
566 BOOLEAN foundDevice
= FALSE
;
569 // Call port driver to get adapter capabilities.
572 status
= ScsiClassGetCapabilities(PortDeviceObject
, &portCapabilities
);
574 if (!NT_SUCCESS(status
)) {
575 DebugPrint((1,"FindScsiDevices: ScsiClassGetCapabilities failed\n"));
580 // Call port driver to get inquiry information to find cdroms.
583 status
= ScsiClassGetInquiryData(PortDeviceObject
, (PSCSI_ADAPTER_BUS_INFO
*) &buffer
);
585 if (!NT_SUCCESS(status
)) {
586 DebugPrint((1,"FindScsiDevices: ScsiClassGetInquiryData failed\n"));
591 // Get the address of the count of the number of cdroms already initialized.
594 cdRomCount
= &IoGetConfigurationInformation()->CdRomCount
;
595 adapterInfo
= (PVOID
) buffer
;
598 // For each SCSI bus this adapter supports ...
601 for (scsiBus
=0; scsiBus
< adapterInfo
->NumberOfBuses
; scsiBus
++) {
604 // Get the SCSI bus scan data for this bus.
607 lunInfo
= (PVOID
) (buffer
+ adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
);
610 // Search list for unclaimed disk devices.
613 while (adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
) {
615 inquiryData
= (PVOID
)lunInfo
->InquiryData
;
617 if ((inquiryData
->DeviceType
== READ_ONLY_DIRECT_ACCESS_DEVICE
) &&
618 (inquiryData
->DeviceTypeQualifier
== 0) &&
619 (!lunInfo
->DeviceClaimed
)) {
621 DebugPrint((1,"FindScsiDevices: Vendor string is %.24s\n",
622 inquiryData
->VendorId
));
625 // Create device objects for cdrom
628 status
= CreateCdRomDeviceObject(DriverObject
,
637 if (NT_SUCCESS(status
)) {
640 // Increment system cdrom device count.
646 // Indicate that a cdrom device was found.
657 if (lunInfo
->NextInquiryDataOffset
== 0) {
661 lunInfo
= (PVOID
) (buffer
+ lunInfo
->NextInquiryDataOffset
);
670 } // end FindScsiCdRoms()
674 CdRomCreateNamedEvent(
675 IN PDEVICE_EXTENSION DeviceExtension
,
676 IN ULONG DeviceNumber
683 Create the named synchronization event for notification of media change
684 events to the system. The event is reset before this function returns.
688 DeviceExtension - the device extension pointer for storage of the event pointer.
697 UNICODE_STRING unicodeString
;
698 OBJECT_ATTRIBUTES objectAttributes
;
699 CCHAR eventNameBuffer
[MAXIMUM_FILENAME_LENGTH
];
700 STRING eventNameString
;
705 sprintf(eventNameBuffer
,"\\Device\\MediaChangeEvent%ld",
708 RtlInitString(&eventNameString
,
711 status
= RtlAnsiStringToUnicodeString(&unicodeString
,
715 if (!NT_SUCCESS(status
)) {
719 InitializeObjectAttributes(&objectAttributes
,
721 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
725 DeviceExtension
->MediaChangeEvent
= IoCreateSynchronizationEvent(&unicodeString
,
727 DeviceExtension
->MediaChangeEventHandle
= handle
;
729 KeClearEvent(DeviceExtension
->MediaChangeEvent
);
731 RtlFreeUnicodeString(&unicodeString
);
736 CreateCdRomDeviceObject(
737 IN PDRIVER_OBJECT DriverObject
,
738 IN PDEVICE_OBJECT PortDeviceObject
,
740 IN PULONG DeviceCount
,
741 IN PIO_SCSI_CAPABILITIES PortCapabilities
,
742 IN PSCSI_INQUIRY_DATA LunInfo
,
743 IN PCLASS_INIT_DATA InitializationData
,
744 IN PUNICODE_STRING RegistryPath
751 This routine creates an object for the device and then calls the
752 SCSI port driver for media capacity and sector size.
756 DriverObject - Pointer to driver object created by system.
757 PortDeviceObject - to connect to SCSI port driver.
758 DeviceCount - Number of previously installed CDROMs.
759 PortCapabilities - Pointer to structure returned by SCSI port
760 driver describing adapter capabilites (and limitations).
761 LunInfo - Pointer to configuration information for this device.
769 CHAR ntNameBuffer
[64];
771 BOOLEAN changerDevice
;
772 SCSI_REQUEST_BLOCK srb
;
776 PVOID senseData
= NULL
;
777 PDEVICE_OBJECT deviceObject
= NULL
;
778 PDEVICE_EXTENSION deviceExtension
= NULL
;
783 BOOLEAN srbListInitialized
= FALSE
;
786 // Claim the device. Note that any errors after this
787 // will goto the generic handler, where the device will
791 status
= ScsiClassClaimDevice(PortDeviceObject
,
796 if (!NT_SUCCESS(status
)) {
801 // Create device object for this device.
804 sprintf(ntNameBuffer
,
805 "\\Device\\CdRom%lu",
808 status
= ScsiClassCreateDeviceObject(DriverObject
,
814 if (!NT_SUCCESS(status
)) {
815 DebugPrint((1,"CreateCdRomDeviceObjects: Can not create device %s\n",
818 goto CreateCdRomDeviceObjectExit
;
822 // Indicate that IRPs should include MDLs.
825 deviceObject
->Flags
|= DO_DIRECT_IO
;
828 // Set up required stack size in device object.
831 deviceObject
->StackSize
= PortDeviceObject
->StackSize
+ 2;
833 deviceExtension
= deviceObject
->DeviceExtension
;
836 // Allocate spinlock for split request completion.
839 KeInitializeSpinLock(&deviceExtension
->SplitRequestSpinLock
);
842 // This is the physical device.
845 deviceExtension
->PhysicalDevice
= deviceObject
;
848 // Initialize lock count to zero. The lock count is used to
849 // disable the ejection mechanism when media is mounted.
852 deviceExtension
->LockCount
= 0;
855 // Save system cdrom number
858 deviceExtension
->DeviceNumber
= *DeviceCount
;
861 // Copy port device object to device extension.
864 deviceExtension
->PortDeviceObject
= PortDeviceObject
;
867 // Set the alignment requirements for the device based on the
868 // host adapter requirements
871 if (PortDeviceObject
->AlignmentRequirement
> deviceObject
->AlignmentRequirement
) {
872 deviceObject
->AlignmentRequirement
= PortDeviceObject
->AlignmentRequirement
;
876 // Save address of port driver capabilities.
879 deviceExtension
->PortCapabilities
= PortCapabilities
;
885 deviceExtension
->SrbFlags
= 0;
886 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
889 // Allocate request sense buffer.
892 senseData
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
894 if (senseData
== NULL
) {
897 // The buffer cannot be allocated.
900 status
= STATUS_INSUFFICIENT_RESOURCES
;
901 goto CreateCdRomDeviceObjectExit
;
905 // Set the sense data pointer in the device extension.
908 deviceExtension
->SenseData
= senseData
;
911 // CDROMs are not partitionable so starting offset is 0.
914 deviceExtension
->StartingOffset
.LowPart
= 0;
915 deviceExtension
->StartingOffset
.HighPart
= 0;
918 // Path/TargetId/LUN describes a device location on the SCSI bus.
919 // This information comes from the LunInfo buffer.
922 deviceExtension
->PortNumber
= (UCHAR
)PortNumber
;
923 deviceExtension
->PathId
= LunInfo
->PathId
;
924 deviceExtension
->TargetId
= LunInfo
->TargetId
;
925 deviceExtension
->Lun
= LunInfo
->Lun
;
928 // Set timeout value in seconds.
931 timeOut
= ScsiClassQueryTimeOutRegistryValue(RegistryPath
);
933 deviceExtension
->TimeOutValue
= timeOut
;
935 deviceExtension
->TimeOutValue
= SCSI_CDROM_TIMEOUT
;
939 // Build the lookaside list for srb's for the physical disk. Should only
943 ScsiClassInitializeSrbLookasideList(deviceExtension
,
944 CDROM_SRB_LIST_SIZE
);
946 srbListInitialized
= TRUE
;
949 // Back pointer to device object.
952 deviceExtension
->DeviceObject
= deviceObject
;
955 // Allocate buffer for drive geometry.
958 deviceExtension
->DiskGeometry
=
959 ExAllocatePool(NonPagedPool
, sizeof(DISK_GEOMETRY_EX
));
961 if (deviceExtension
->DiskGeometry
== NULL
) {
963 status
= STATUS_INSUFFICIENT_RESOURCES
;
964 goto CreateCdRomDeviceObjectExit
;
968 // Set up media change support defaults.
971 cddata
= (PCDROM_DATA
)(deviceExtension
+ 1);
973 KeInitializeSpinLock(&cddata
->FormSpinLock
);
974 KeInitializeSpinLock(&cddata
->TimerIrpSpinLock
);
975 InitializeListHead(&cddata
->TimerIrpList
);
977 cddata
->MediaChangeCountDown
= MEDIA_CHANGE_DEFAULT_TIME
;
978 cddata
->MediaChangeSupported
= FALSE
;
979 cddata
->MediaChange
= FALSE
;
982 // Assume that there is initially no media in the device
983 // only notify upper layers if there is something there
986 deviceExtension
->MediaChangeNoMedia
= TRUE
;
987 cddata
->MediaChangeIrp
= NULL
;
989 cddata
->MediaChangeIrpTimeInUse
= 0;
990 cddata
->MediaChangeIrpLost
= FALSE
;
994 // Scan for Scsi controllers that require special processing.
997 ScanForSpecial(deviceObject
,
998 (PINQUIRYDATA
) LunInfo
->InquiryData
,
1002 // Do READ CAPACITY. This SCSI command
1003 // returns the last sector address on the device
1004 // and the bytes per sector.
1005 // These are used to calculate the drive capacity
1009 status
= ScsiClassReadDriveCapacity(deviceObject
);
1010 bps
= deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
;
1012 if (!NT_SUCCESS(status
) || !bps
) {
1015 "CreateCdRomDeviceObjects: Can't read capacity for device %s\n",
1019 // Set disk geometry to default values (per ISO 9660).
1023 deviceExtension
->SectorShift
= 11;
1024 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(0x7fffffff);
1028 // Insure that bytes per sector is a power of 2
1029 // This corrects a problem with the HP 4020i CDR where it
1030 // returns an incorrect number for bytes per sector.
1033 lastBit
= (ULONG
) -1;
1041 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= bps
;
1042 DebugPrint((2, "CreateCdRomDeviceObject: Calc'd bps = %x\n", bps
));
1045 // Check to see if this is some sort of changer device
1048 changerDevice
= FALSE
;
1051 // Search for devices that have special requirements for media
1055 if (deviceExtension
->Lun
> 0) {
1056 changerDevice
= TRUE
;
1059 if (!changerDevice
) {
1060 changerDevice
= IsThisASanyo(deviceObject
, deviceExtension
->PathId
,
1061 deviceExtension
->TargetId
);
1064 if (!changerDevice
) {
1066 changerDevice
= IsThisAnAtapiChanger(deviceObject
, &tmp
);
1069 if (!changerDevice
) {
1070 changerDevice
= IsThisAMultiLunDevice(deviceObject
, PortDeviceObject
);
1074 // If it is a changer device, increment the timeout to take platter-swapping
1075 // time into account
1079 deviceExtension
->TimeOutValue
+= SCSI_CHANGER_BONUS_TIMEOUT
;
1083 // Create the media change named event. If this succeeds then continue
1084 // initializing the media change support data items.
1087 CdRomCreateNamedEvent(deviceExtension
,*DeviceCount
);
1088 if (deviceExtension
->MediaChangeEvent
) {
1091 // If this is not a changer, get an IRP for the timer request
1092 // and initialize the timer.
1095 if (!changerDevice
) {
1098 // Not a changer device - continue with media change initialization.
1099 // Determine if the user actually wants media change events.
1102 if (CdRomCheckRegistryForMediaChangeValue(RegistryPath
, *DeviceCount
)) {
1103 PIO_STACK_LOCATION irpStack
;
1104 PSCSI_REQUEST_BLOCK srb
;
1108 // User wants it - preallocate IRP and SRB.
1111 irp
= IoAllocateIrp((CCHAR
)(deviceObject
->StackSize
+1),
1116 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
1117 buffer
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
1119 if (srb
&& buffer
) {
1123 // All resources have been allocated set up the IRP.
1126 IoSetNextIrpStackLocation(irp
);
1127 irpStack
= IoGetCurrentIrpStackLocation(irp
);
1128 irpStack
->DeviceObject
= deviceObject
;
1129 irpStack
= IoGetNextIrpStackLocation(irp
);
1130 cddata
->MediaChangeIrp
= irp
;
1131 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1134 // Initialize the SRB
1137 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
1140 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
* 2;
1141 srb
->QueueTag
= SP_UNTAGGED
;
1142 srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
1143 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1144 srb
->PathId
= deviceExtension
->PathId
;
1145 srb
->TargetId
= deviceExtension
->TargetId
;
1146 srb
->Lun
= deviceExtension
->Lun
;
1147 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1150 // Initialize and set up the sense information buffer
1153 RtlZeroMemory(buffer
, SENSE_BUFFER_SIZE
);
1154 srb
->SenseInfoBuffer
= buffer
;
1155 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1158 // Initialize the CDB
1161 cdb
= (PCDB
)&srb
->Cdb
[0];
1162 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_TEST_UNIT_READY
;
1163 cdb
->CDB6GENERIC
.LogicalUnitNumber
= deviceExtension
->Lun
;
1166 // It is ok to support media change events on this device.
1169 cddata
->MediaChangeSupported
= TRUE
;
1170 cddata
->MediaChange
= TRUE
;
1184 deviceExtension
->MediaChangeEvent
= NULL
;
1187 deviceExtension
->MediaChangeEvent
= NULL
;
1192 // Assume use of 6-byte mode sense/select for now.
1195 cddata
->XAFlags
|= XA_USE_6_BYTE
;
1198 // Build and issue mode sense with Read error recovery page. This will be used to change
1199 // block size in case of any raw reads (Mode 2, Form 2).
1202 length
= (sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH
);
1204 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
1207 cdb
= (PCDB
)srb
.Cdb
;
1210 // Set timeout value from device extension.
1213 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
1216 // Build the MODE SENSE CDB. The data returned will be kept in the device extension
1217 // and used to set block size.
1220 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
1221 cdb
->MODE_SENSE
.PageCode
= 0x1;
1222 cdb
->MODE_SENSE
.AllocationLength
= (UCHAR
)length
;
1224 buffer
= ExAllocatePool(NonPagedPoolCacheAligned
, (sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH10
));
1226 status
= STATUS_INSUFFICIENT_RESOURCES
;
1227 goto CreateCdRomDeviceObjectExit
;
1230 status
= ScsiClassSendSrbSynchronous(deviceObject
,
1235 if (!NT_SUCCESS(status
)) {
1238 // May be Atapi, try 10-byte.
1241 length
= (sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH10
);
1243 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
1246 // Build the MODE SENSE CDB.
1250 cdb
= (PCDB
)srb
.Cdb
;
1253 // Set timeout value from device extension.
1256 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
1258 cdb
->MODE_SENSE10
.OperationCode
= SCSIOP_MODE_SENSE10
;
1259 cdb
->MODE_SENSE10
.PageCode
= 0x1;
1261 cdb
->MODE_SENSE10
.AllocationLength
[0] = (UCHAR
)(length
>> 8);
1262 cdb
->MODE_SENSE10
.AllocationLength
[1] = (UCHAR
)(length
& 0xFF);
1264 status
= ScsiClassSendSrbSynchronous(deviceObject
,
1269 if (status
== STATUS_DATA_OVERRUN
) {
1272 // Build and issue the ReadCd command to ensure that this device supports it.
1275 RtlZeroMemory(cdb
, 12);
1277 cdb
->READ_CD
.OperationCode
= SCSIOP_READ_CD
;
1279 status
= ScsiClassSendSrbSynchronous(deviceObject
,
1286 // If the command wasn't rejected then support the READ_CD.
1289 if (NT_SUCCESS(status
) || (status
== STATUS_NO_MEDIA_IN_DEVICE
)) {
1292 // Using Read CD precludes issueing a mode select to
1293 // set the user data size. So, no buffer copy is
1297 cddata
->XAFlags
&= ~XA_USE_6_BYTE
;
1298 cddata
->XAFlags
|= XA_USE_READ_CD
| XA_USE_10_BYTE
;
1301 RtlCopyMemory(&cddata
->u1
.Header
, buffer
, sizeof(ERROR_RECOVERY_DATA10
));
1302 cddata
->u1
.Header
.ModeDataLength
= 0;
1304 cddata
->XAFlags
&= ~XA_USE_6_BYTE
;
1305 cddata
->XAFlags
|= XA_USE_10_BYTE
;
1308 } else if (NT_SUCCESS(status
)) {
1310 RtlCopyMemory(&cddata
->u1
.Header
, buffer
, sizeof(ERROR_RECOVERY_DATA10
));
1311 cddata
->u1
.Header
.ModeDataLength
= 0;
1313 cddata
->XAFlags
&= ~XA_USE_6_BYTE
;
1314 cddata
->XAFlags
|= XA_USE_10_BYTE
;
1317 cddata
->XAFlags
|= XA_NOT_SUPPORTED
;
1320 RtlCopyMemory(&cddata
->u1
.Header
, buffer
, sizeof(ERROR_RECOVERY_DATA
));
1321 cddata
->u1
.Header
.ModeDataLength
= 0;
1327 // Start the timer now regardless of if Autorun is enabled.
1328 // The timer must run forever since IoStopTimer faults.
1331 IoInitializeTimer(deviceObject
, CdRomTickHandler
, NULL
);
1332 IoStartTimer(deviceObject
);
1334 return(STATUS_SUCCESS
);
1336 CreateCdRomDeviceObjectExit
:
1339 // Release the device since an error occured.
1342 ScsiClassClaimDevice(PortDeviceObject
,
1347 if (senseData
!= NULL
) {
1348 ExFreePool(senseData
);
1351 if (deviceExtension
->DiskGeometry
!= NULL
) {
1352 ExFreePool(deviceExtension
->DiskGeometry
);
1355 if (deviceObject
!= NULL
) {
1356 if (srbListInitialized
) {
1357 ExDeleteNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
);
1359 IoDeleteDevice(deviceObject
);
1365 } // end CreateCdRomDeviceObject()
1370 IN PDEVICE_OBJECT DeviceObject
,
1375 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1376 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1377 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
1378 PIO_STACK_LOCATION irpStack
;
1380 ULONG transferPages
;
1381 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
1382 ULONG maximumTransferLength
= deviceExtension
->PortCapabilities
->MaximumTransferLength
;
1384 PSCSI_REQUEST_BLOCK srb
= NULL
;
1386 PUCHAR senseBuffer
= NULL
;
1392 // Mark IRP with status pending.
1395 IoMarkIrpPending(Irp
);
1398 // If the flag is set in the device object, force a verify.
1401 if (DeviceObject
->Flags
& DO_VERIFY_VOLUME
) {
1402 DebugPrint((2, "ScsiCdRomStartIo: [%lx] Volume needs verified\n", Irp
));
1403 if (!(currentIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
)) {
1405 if (Irp
->Tail
.Overlay
.Thread
) {
1406 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
1409 Irp
->IoStatus
.Status
= STATUS_VERIFY_REQUIRED
;
1411 DebugPrint((2, "ScsiCdRomStartIo: [%lx] Calling UpdateCapcity - "
1412 "ioctl event = %lx\n",
1414 nextIrpStack
->Parameters
.Others
.Argument1
1418 // our device control dispatch routine stores an event in the next
1419 // stack location to signal when startio has completed. We need to
1420 // pass this in so that the update capacity completion routine can
1421 // set it rather than completing the Irp.
1424 status
= CdRomUpdateCapacity(deviceExtension
,
1426 nextIrpStack
->Parameters
.Others
.Argument1
1429 DebugPrint((2, "ScsiCdRomStartIo: [%lx] UpdateCapacity returned %lx\n", Irp
, status
));
1430 ASSERT(status
== STATUS_PENDING
);
1435 cdData
= (PCDROM_DATA
)(deviceExtension
+ 1);
1436 use6Byte
= cdData
->XAFlags
& XA_USE_6_BYTE
;
1438 if (currentIrpStack
->MajorFunction
== IRP_MJ_READ
) {
1441 // Add partition byte offset to make starting byte relative to
1442 // beginning of disk. In addition, add in skew for DM Driver, if any.
1445 currentIrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+= (deviceExtension
->StartingOffset
.QuadPart
);
1448 // Calculate number of pages in this transfer.
1451 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp
->MdlAddress
),
1452 currentIrpStack
->Parameters
.Read
.Length
);
1455 // Check if request length is greater than the maximum number of
1456 // bytes that the hardware can transfer.
1459 if (cdData
->RawAccess
) {
1461 ASSERT(!(cdData
->XAFlags
& XA_USE_READ_CD
));
1464 // Fire off a mode select to switch back to cooked sectors.
1467 irp2
= IoAllocateIrp((CCHAR
)(deviceExtension
->DeviceObject
->StackSize
+1),
1471 Irp
->IoStatus
.Information
= 0;
1472 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1473 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1474 IoStartNextPacket(DeviceObject
, FALSE
);
1478 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
1480 Irp
->IoStatus
.Information
= 0;
1481 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1482 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1484 IoStartNextPacket(DeviceObject
, FALSE
);
1488 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
1490 cdb
= (PCDB
)srb
->Cdb
;
1493 // Allocate sense buffer.
1496 senseBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
1499 Irp
->IoStatus
.Information
= 0;
1500 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1501 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1504 IoStartNextPacket(DeviceObject
, FALSE
);
1512 IoSetNextIrpStackLocation(irp2
);
1513 irp2
->IoStatus
.Status
= STATUS_SUCCESS
;
1514 irp2
->IoStatus
.Information
= 0;
1516 irp2
->UserBuffer
= NULL
;
1519 // Save the device object and irp in a private stack location.
1522 irpStack
= IoGetCurrentIrpStackLocation(irp2
);
1523 irpStack
->DeviceObject
= deviceExtension
->DeviceObject
;
1524 irpStack
->Parameters
.Others
.Argument2
= (PVOID
) Irp
;
1527 // The retry count will be in the real Irp, as the retry logic will
1528 // recreate our private irp.
1531 if (!(nextIrpStack
->Parameters
.Others
.Argument1
)) {
1534 // Only jam this in if it doesn't exist. The completion routines can
1535 // call StartIo directly in the case of retries and resetting it will
1536 // cause infinite loops.
1539 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
1543 // Construct the IRP stack for the lower level driver.
1546 irpStack
= IoGetNextIrpStackLocation(irp2
);
1547 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
1548 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
1549 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1551 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1552 srb
->PathId
= deviceExtension
->PathId
;
1553 srb
->TargetId
= deviceExtension
->TargetId
;
1554 srb
->Lun
= deviceExtension
->Lun
;
1555 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1556 srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
1557 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
1559 srb
->OriginalRequest
= irp2
;
1560 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1561 srb
->SenseInfoBuffer
= senseBuffer
;
1563 transferByteCount
= (use6Byte
) ? sizeof(ERROR_RECOVERY_DATA
) : sizeof(ERROR_RECOVERY_DATA10
);
1564 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, transferByteCount
);
1566 Irp
->IoStatus
.Information
= 0;
1567 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1568 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1569 ExFreePool(senseBuffer
);
1572 IoStartNextPacket(DeviceObject
, FALSE
);
1577 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
1583 if (!irp2
->MdlAddress
) {
1584 Irp
->IoStatus
.Information
= 0;
1585 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1586 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1587 ExFreePool(senseBuffer
);
1589 ExFreePool(dataBuffer
);
1591 IoStartNextPacket(DeviceObject
, FALSE
);
1599 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
1601 srb
->DataBuffer
= dataBuffer
;
1604 // Set the new block size in the descriptor.
1607 cdData
->u1
.BlockDescriptor
.BlockLength
[0] = (UCHAR
)(COOKED_SECTOR_SIZE
>> 16) & 0xFF;
1608 cdData
->u1
.BlockDescriptor
.BlockLength
[1] = (UCHAR
)(COOKED_SECTOR_SIZE
>> 8) & 0xFF;
1609 cdData
->u1
.BlockDescriptor
.BlockLength
[2] = (UCHAR
)(COOKED_SECTOR_SIZE
& 0xFF);
1612 // Move error page into dataBuffer.
1615 RtlCopyMemory(srb
->DataBuffer
, &cdData
->u1
.Header
, transferByteCount
);
1618 // Build and send a mode select to switch into raw mode.
1621 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
1622 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_OUT
);
1623 srb
->DataTransferLength
= transferByteCount
;
1624 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
* 2;
1628 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
1629 cdb
->MODE_SELECT
.PFBit
= 1;
1630 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)transferByteCount
;
1633 srb
->CdbLength
= 10;
1634 cdb
->MODE_SELECT10
.OperationCode
= SCSIOP_MODE_SELECT10
;
1635 cdb
->MODE_SELECT10
.PFBit
= 1;
1636 cdb
->MODE_SELECT10
.ParameterListLength
[0] = (UCHAR
)(transferByteCount
>> 8);
1637 cdb
->MODE_SELECT10
.ParameterListLength
[1] = (UCHAR
)(transferByteCount
& 0xFF);
1641 // Update completion routine.
1644 IoSetCompletionRoutine(irp2
,
1645 CdRomSwitchModeCompletion
,
1651 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
1655 if ((currentIrpStack
->Parameters
.Read
.Length
> maximumTransferLength
) ||
1657 deviceExtension
->PortCapabilities
->MaximumPhysicalPages
)) {
1660 // Request needs to be split. Completion of each portion of the
1661 // request will fire off the next portion. The final request will
1662 // signal Io to send a new request.
1666 deviceExtension
->PortCapabilities
->MaximumPhysicalPages
- 1;
1668 if(maximumTransferLength
> transferPages
<< PAGE_SHIFT
) {
1669 maximumTransferLength
= transferPages
<< PAGE_SHIFT
;
1673 // Check that the maximum transfer size is not zero
1676 if(maximumTransferLength
== 0) {
1677 maximumTransferLength
= PAGE_SIZE
;
1680 ScsiClassSplitRequest(DeviceObject
, Irp
, maximumTransferLength
);
1686 // Build SRB and CDB for this IRP.
1689 ScsiClassBuildRequest(DeviceObject
, Irp
);
1694 } else if (currentIrpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
) {
1697 // Allocate an irp, srb and associated structures.
1700 irp2
= IoAllocateIrp((CCHAR
)(deviceExtension
->DeviceObject
->StackSize
+1),
1704 Irp
->IoStatus
.Information
= 0;
1705 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1706 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1707 IoStartNextPacket(DeviceObject
, FALSE
);
1708 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp
, Irp
->IoStatus
.Status
, __LINE__
));
1712 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
1714 Irp
->IoStatus
.Information
= 0;
1715 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1716 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1718 IoStartNextPacket(DeviceObject
, FALSE
);
1719 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp
, Irp
->IoStatus
.Status
, __LINE__
));
1723 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
1725 cdb
= (PCDB
)srb
->Cdb
;
1728 // Allocate sense buffer.
1731 senseBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
1734 Irp
->IoStatus
.Information
= 0;
1735 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1736 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1739 IoStartNextPacket(DeviceObject
, FALSE
);
1740 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp
, Irp
->IoStatus
.Status
, __LINE__
));
1748 IoSetNextIrpStackLocation(irp2
);
1749 irp2
->IoStatus
.Status
= STATUS_SUCCESS
;
1750 irp2
->IoStatus
.Information
= 0;
1752 irp2
->UserBuffer
= NULL
;
1755 // Save the device object and irp in a private stack location.
1758 irpStack
= IoGetCurrentIrpStackLocation(irp2
);
1759 irpStack
->DeviceObject
= deviceExtension
->DeviceObject
;
1760 irpStack
->Parameters
.Others
.Argument2
= (PVOID
) Irp
;
1763 // The retry count will be in the real Irp, as the retry logic will
1764 // recreate our private irp.
1767 if (!(nextIrpStack
->Parameters
.Others
.Argument1
)) {
1770 // Only jam this in if it doesn't exist. The completion routines can
1771 // call StartIo directly in the case of retries and resetting it will
1772 // cause infinite loops.
1775 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
1779 // Construct the IRP stack for the lower level driver.
1782 irpStack
= IoGetNextIrpStackLocation(irp2
);
1783 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
1784 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
1785 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1787 IoSetCompletionRoutine(irp2
,
1788 CdRomDeviceControlCompletion
,
1794 // Setup those fields that are generic to all requests.
1797 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1798 srb
->PathId
= deviceExtension
->PathId
;
1799 srb
->TargetId
= deviceExtension
->TargetId
;
1800 srb
->Lun
= deviceExtension
->Lun
;
1801 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1802 srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
1803 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
1805 srb
->OriginalRequest
= irp2
;
1806 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1807 srb
->SenseInfoBuffer
= senseBuffer
;
1809 switch (currentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
) {
1811 case IOCTL_CDROM_RAW_READ
: {
1814 // Determine whether the drive is currently in raw or cooked mode,
1815 // and which command to use to read the data.
1818 if (!(cdData
->XAFlags
& XA_USE_READ_CD
)) {
1820 PRAW_READ_INFO rawReadInfo
=
1821 (PRAW_READ_INFO
)currentIrpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
1822 ULONG maximumTransferLength
;
1823 ULONG transferPages
;
1825 if (cdData
->RawAccess
) {
1827 ULONG startingSector
;
1830 // Free the recently allocated irp, as we don't need it.
1835 cdb
= (PCDB
)srb
->Cdb
;
1836 RtlZeroMemory(cdb
, 12);
1839 // Calculate starting offset.
1842 startingSector
= (ULONG
)(rawReadInfo
->DiskOffset
.QuadPart
>> deviceExtension
->SectorShift
);
1843 transferByteCount
= rawReadInfo
->SectorCount
* RAW_SECTOR_SIZE
;
1844 maximumTransferLength
= deviceExtension
->PortCapabilities
->MaximumTransferLength
;
1845 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp
->MdlAddress
),
1849 // Determine if request is within limits imposed by miniport.
1852 if (transferByteCount
> maximumTransferLength
||
1853 transferPages
> deviceExtension
->PortCapabilities
->MaximumPhysicalPages
) {
1856 // The claim is that this won't happen, and is backed up by
1857 // ActiveMovie usage, which does unbuffered XA reads of 0x18000, yet
1858 // we get only 4 sector requests.
1862 Irp
->IoStatus
.Information
= 0;
1863 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
1864 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1865 ExFreePool(senseBuffer
);
1867 IoStartNextPacket(DeviceObject
, FALSE
);
1872 srb
->OriginalRequest
= Irp
;
1873 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
1874 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
1875 srb
->DataTransferLength
= transferByteCount
;
1876 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
1877 srb
->CdbLength
= 10;
1878 srb
->DataBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
1880 if (rawReadInfo
->TrackMode
== CDDA
) {
1881 if (cdData
->XAFlags
& PLEXTOR_CDDA
) {
1883 srb
->CdbLength
= 12;
1885 cdb
->PLXTR_READ_CDDA
.LogicalUnitNumber
= deviceExtension
->Lun
;
1886 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
1887 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
1888 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
1889 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
1891 cdb
->PLXTR_READ_CDDA
.TransferBlockByte3
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
1892 cdb
->PLXTR_READ_CDDA
.TransferBlockByte2
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
1893 cdb
->PLXTR_READ_CDDA
.TransferBlockByte1
= 0;
1894 cdb
->PLXTR_READ_CDDA
.TransferBlockByte0
= 0;
1896 cdb
->PLXTR_READ_CDDA
.SubCode
= 0;
1897 cdb
->PLXTR_READ_CDDA
.OperationCode
= 0xD8;
1899 } else if (cdData
->XAFlags
& NEC_CDDA
) {
1901 cdb
->NEC_READ_CDDA
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
1902 cdb
->NEC_READ_CDDA
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
1903 cdb
->NEC_READ_CDDA
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
1904 cdb
->NEC_READ_CDDA
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
1906 cdb
->NEC_READ_CDDA
.TransferBlockByte1
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
1907 cdb
->NEC_READ_CDDA
.TransferBlockByte0
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
1909 cdb
->NEC_READ_CDDA
.OperationCode
= 0xD4;
1913 cdb
->CDB10
.LogicalUnitNumber
= deviceExtension
->Lun
;
1915 cdb
->CDB10
.TransferBlocksMsb
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
1916 cdb
->CDB10
.TransferBlocksLsb
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
1918 cdb
->CDB10
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
1919 cdb
->CDB10
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
1920 cdb
->CDB10
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
1921 cdb
->CDB10
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
1923 cdb
->CDB10
.OperationCode
= SCSIOP_READ
;
1926 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
1928 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
1929 nextIrpStack
->Parameters
.Scsi
.Srb
= srb
;
1931 if (!(nextIrpStack
->Parameters
.Others
.Argument1
)) {
1934 // Only jam this in if it doesn't exist. The completion routines can
1935 // call StartIo directly in the case of retries and resetting it will
1936 // cause infinite loops.
1939 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
1943 // Set up IoCompletion routine address.
1946 IoSetCompletionRoutine(Irp
,
1953 IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
1958 transferByteCount
= (use6Byte
) ? sizeof(ERROR_RECOVERY_DATA
) : sizeof(ERROR_RECOVERY_DATA10
);
1959 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, transferByteCount
);
1961 Irp
->IoStatus
.Information
= 0;
1962 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1963 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1964 ExFreePool(senseBuffer
);
1967 IoStartNextPacket(DeviceObject
, FALSE
);
1972 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
1978 if (!irp2
->MdlAddress
) {
1979 Irp
->IoStatus
.Information
= 0;
1980 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1981 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1982 ExFreePool(senseBuffer
);
1984 ExFreePool(dataBuffer
);
1986 IoStartNextPacket(DeviceObject
, FALSE
);
1994 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
1996 srb
->DataBuffer
= dataBuffer
;
1999 // Set the new block size in the descriptor.
2002 cdData
->u1
.BlockDescriptor
.BlockLength
[0] = (UCHAR
)(RAW_SECTOR_SIZE
>> 16) & 0xFF;
2003 cdData
->u1
.BlockDescriptor
.BlockLength
[1] = (UCHAR
)(RAW_SECTOR_SIZE
>> 8) & 0xFF;
2004 cdData
->u1
.BlockDescriptor
.BlockLength
[2] = (UCHAR
)(RAW_SECTOR_SIZE
& 0xFF);
2008 // TODO: Set density code, based on operation
2011 cdData
->u1
.BlockDescriptor
.DensityCode
= 0;
2015 // Move error page into dataBuffer.
2018 RtlCopyMemory(srb
->DataBuffer
, &cdData
->u1
.Header
, transferByteCount
);
2022 // Build and send a mode select to switch into raw mode.
2025 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2026 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_OUT
);
2027 srb
->DataTransferLength
= transferByteCount
;
2028 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
* 2;
2032 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
2033 cdb
->MODE_SELECT
.PFBit
= 1;
2034 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)transferByteCount
;
2037 srb
->CdbLength
= 10;
2038 cdb
->MODE_SELECT10
.OperationCode
= SCSIOP_MODE_SELECT10
;
2039 cdb
->MODE_SELECT10
.PFBit
= 1;
2040 cdb
->MODE_SELECT10
.ParameterListLength
[0] = (UCHAR
)(transferByteCount
>> 8);
2041 cdb
->MODE_SELECT10
.ParameterListLength
[1] = (UCHAR
)(transferByteCount
& 0xFF);
2045 // Update completion routine.
2048 IoSetCompletionRoutine(irp2
,
2049 CdRomSwitchModeCompletion
,
2059 PRAW_READ_INFO rawReadInfo
=
2060 (PRAW_READ_INFO
)currentIrpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
2061 ULONG startingSector
;
2064 // Free the recently allocated irp, as we don't need it.
2069 cdb
= (PCDB
)srb
->Cdb
;
2070 RtlZeroMemory(cdb
, 12);
2074 // Calculate starting offset.
2077 startingSector
= (ULONG
)(rawReadInfo
->DiskOffset
.QuadPart
>> deviceExtension
->SectorShift
);
2078 transferByteCount
= rawReadInfo
->SectorCount
* RAW_SECTOR_SIZE
;
2081 srb
->OriginalRequest
= Irp
;
2082 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2083 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
2084 srb
->DataTransferLength
= transferByteCount
;
2085 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2086 srb
->DataBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
2087 srb
->CdbLength
= 12;
2088 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
2091 // Fill in CDB fields.
2094 cdb
= (PCDB
)srb
->Cdb
;
2097 cdb
->READ_CD
.TransferBlocks
[2] = (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
2098 cdb
->READ_CD
.TransferBlocks
[1] = (UCHAR
) (rawReadInfo
->SectorCount
>> 8 );
2099 cdb
->READ_CD
.TransferBlocks
[0] = (UCHAR
) (rawReadInfo
->SectorCount
>> 16);
2102 cdb
->READ_CD
.StartingLBA
[3] = (UCHAR
) (startingSector
& 0xFF);
2103 cdb
->READ_CD
.StartingLBA
[2] = (UCHAR
) ((startingSector
>> 8));
2104 cdb
->READ_CD
.StartingLBA
[1] = (UCHAR
) ((startingSector
>> 16));
2105 cdb
->READ_CD
.StartingLBA
[0] = (UCHAR
) ((startingSector
>> 24));
2108 // Setup cdb depending upon the sector type we want.
2111 switch (rawReadInfo
->TrackMode
) {
2114 cdb
->READ_CD
.ExpectedSectorType
= CD_DA_SECTOR
;
2115 cdb
->READ_CD
.IncludeUserData
= 1;
2116 cdb
->READ_CD
.HeaderCode
= 3;
2117 cdb
->READ_CD
.IncludeSyncData
= 1;
2122 cdb
->READ_CD
.ExpectedSectorType
= YELLOW_MODE2_SECTOR
;
2123 cdb
->READ_CD
.IncludeUserData
= 1;
2124 cdb
->READ_CD
.HeaderCode
= 1;
2125 cdb
->READ_CD
.IncludeSyncData
= 1;
2130 cdb
->READ_CD
.ExpectedSectorType
= FORM2_MODE2_SECTOR
;
2131 cdb
->READ_CD
.IncludeUserData
= 1;
2132 cdb
->READ_CD
.HeaderCode
= 3;
2133 cdb
->READ_CD
.IncludeSyncData
= 1;
2137 Irp
->IoStatus
.Information
= 0;
2138 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
2139 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2140 ExFreePool(senseBuffer
);
2142 IoStartNextPacket(DeviceObject
, FALSE
);
2143 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp
, Irp
->IoStatus
.Status
, __LINE__
));
2147 cdb
->READ_CD
.OperationCode
= SCSIOP_READ_CD
;
2149 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
2150 nextIrpStack
->Parameters
.Scsi
.Srb
= srb
;
2152 if (!(nextIrpStack
->Parameters
.Others
.Argument1
)) {
2155 // Only jam this in if it doesn't exist. The completion routines can
2156 // call StartIo directly in the case of retries and resetting it will
2157 // cause infinite loops.
2160 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
2164 // Set up IoCompletion routine address.
2167 IoSetCompletionRoutine(Irp
,
2174 IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
2179 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2183 case IOCTL_DISK_GET_LENGTH_INFO
:
2184 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
2185 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
: {
2188 // Issue ReadCapacity to update device extension
2189 // with information for current media.
2193 "CdRomStartIo: Get drive capacity\n"));
2196 // setup remaining srb and cdb parameters.
2199 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2200 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
2201 srb
->DataTransferLength
= sizeof(READ_CAPACITY_DATA
);
2202 srb
->CdbLength
= 10;
2203 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2205 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, sizeof(READ_CAPACITY_DATA
));
2207 Irp
->IoStatus
.Information
= 0;
2208 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2209 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2210 ExFreePool(senseBuffer
);
2213 IoStartNextPacket(DeviceObject
, FALSE
);
2214 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp
, Irp
->IoStatus
.Status
, __LINE__
));
2219 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2220 sizeof(READ_CAPACITY_DATA
),
2225 if (!irp2
->MdlAddress
) {
2226 Irp
->IoStatus
.Information
= 0;
2227 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2228 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2229 ExFreePool(senseBuffer
);
2231 ExFreePool(dataBuffer
);
2233 IoStartNextPacket(DeviceObject
, FALSE
);
2234 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp
, Irp
->IoStatus
.Status
, __LINE__
));
2242 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2244 srb
->DataBuffer
= dataBuffer
;
2245 cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
2247 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2251 case IOCTL_CDROM_CHECK_VERIFY
: {
2254 // Since a test unit ready is about to be performed, reset the timer
2255 // value to decrease the opportunities for it to race with this code.
2258 cdData
->MediaChangeCountDown
= MEDIA_CHANGE_DEFAULT_TIME
;
2261 // Set up the SRB/CDB
2265 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_TEST_UNIT_READY
;
2266 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
* 2;
2267 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2268 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_NO_DATA_TRANSFER
);
2270 DebugPrint((2, "ScsiCdRomStartIo: [%lx] Sending CHECK_VERIFY irp %lx\n", Irp
, irp2
));
2271 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2275 case IOCTL_CDROM_GET_LAST_SESSION
:
2278 // Set format to return first and last session numbers.
2281 cdb
->READ_TOC
.Format
= GET_LAST_SESSION
;
2284 // Fall through to READ TOC code.
2287 case IOCTL_CDROM_READ_TOC
: {
2290 if (currentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_READ_TOC
) {
2293 // Use MSF addressing if not request for session information.
2296 cdb
->READ_TOC
.Msf
= CDB_USE_MSF
;
2300 // Set size of TOC structure.
2304 currentIrpStack
->Parameters
.Read
.Length
>
2305 sizeof(CDROM_TOC
) ? sizeof(CDROM_TOC
):
2306 currentIrpStack
->Parameters
.Read
.Length
;
2308 cdb
->READ_TOC
.AllocationLength
[0] = (UCHAR
) (transferByteCount
>> 8);
2309 cdb
->READ_TOC
.AllocationLength
[1] = (UCHAR
) (transferByteCount
& 0xFF);
2311 cdb
->READ_TOC
.Control
= 0;
2314 // Start at beginning of disc.
2317 cdb
->READ_TOC
.StartingTrack
= 0;
2320 // setup remaining srb and cdb parameters.
2323 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2324 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
2325 srb
->DataTransferLength
= transferByteCount
;
2326 srb
->CdbLength
= 10;
2327 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2329 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, transferByteCount
);
2331 Irp
->IoStatus
.Information
= 0;
2332 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2333 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2334 ExFreePool(senseBuffer
);
2337 IoStartNextPacket(DeviceObject
, FALSE
);
2342 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2348 if (!irp2
->MdlAddress
) {
2349 Irp
->IoStatus
.Information
= 0;
2350 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2351 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2352 ExFreePool(senseBuffer
);
2354 ExFreePool(dataBuffer
);
2356 IoStartNextPacket(DeviceObject
, FALSE
);
2364 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2366 srb
->DataBuffer
= dataBuffer
;
2367 cdb
->READ_TOC
.OperationCode
= SCSIOP_READ_TOC
;
2369 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2374 case IOCTL_CDROM_PLAY_AUDIO_MSF
: {
2376 PCDROM_PLAY_AUDIO_MSF inputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
2379 // Set up the SRB/CDB
2382 srb
->CdbLength
= 10;
2383 cdb
->PLAY_AUDIO_MSF
.OperationCode
= SCSIOP_PLAY_AUDIO_MSF
;
2385 cdb
->PLAY_AUDIO_MSF
.StartingM
= inputBuffer
->StartingM
;
2386 cdb
->PLAY_AUDIO_MSF
.StartingS
= inputBuffer
->StartingS
;
2387 cdb
->PLAY_AUDIO_MSF
.StartingF
= inputBuffer
->StartingF
;
2389 cdb
->PLAY_AUDIO_MSF
.EndingM
= inputBuffer
->EndingM
;
2390 cdb
->PLAY_AUDIO_MSF
.EndingS
= inputBuffer
->EndingS
;
2391 cdb
->PLAY_AUDIO_MSF
.EndingF
= inputBuffer
->EndingF
;
2393 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2394 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2395 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_NO_DATA_TRANSFER
);
2397 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2402 case IOCTL_CDROM_READ_Q_CHANNEL
: {
2404 PCDROM_SUB_Q_DATA_FORMAT inputBuffer
=
2405 Irp
->AssociatedIrp
.SystemBuffer
;
2408 // Allocate buffer for subq channel information.
2411 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
2412 sizeof(SUB_Q_CHANNEL_DATA
));
2415 Irp
->IoStatus
.Information
= 0;
2416 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2417 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2418 ExFreePool(senseBuffer
);
2421 IoStartNextPacket(DeviceObject
, FALSE
);
2426 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2432 if (!irp2
->MdlAddress
) {
2433 Irp
->IoStatus
.Information
= 0;
2434 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2435 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2436 ExFreePool(senseBuffer
);
2438 ExFreePool(dataBuffer
);
2440 IoStartNextPacket(DeviceObject
, FALSE
);
2448 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2450 srb
->DataBuffer
= dataBuffer
;
2453 // Always logical unit 0, but only use MSF addressing
2454 // for IOCTL_CDROM_CURRENT_POSITION
2457 if (inputBuffer
->Format
==IOCTL_CDROM_CURRENT_POSITION
)
2458 cdb
->SUBCHANNEL
.Msf
= CDB_USE_MSF
;
2461 // Return subchannel data
2464 cdb
->SUBCHANNEL
.SubQ
= CDB_SUBCHANNEL_BLOCK
;
2467 // Specify format of informatin to return
2470 cdb
->SUBCHANNEL
.Format
= inputBuffer
->Format
;
2473 // Specify which track to access (only used by Track ISRC reads)
2476 if (inputBuffer
->Format
==IOCTL_CDROM_TRACK_ISRC
) {
2477 cdb
->SUBCHANNEL
.TrackNumber
= inputBuffer
->Track
;
2481 // Set size of channel data -- however, this is dependent on
2482 // what information we are requesting (which Format)
2485 switch( inputBuffer
->Format
) {
2487 case IOCTL_CDROM_CURRENT_POSITION
:
2488 transferByteCount
= sizeof(SUB_Q_CURRENT_POSITION
);
2491 case IOCTL_CDROM_MEDIA_CATALOG
:
2492 transferByteCount
= sizeof(SUB_Q_MEDIA_CATALOG_NUMBER
);
2495 case IOCTL_CDROM_TRACK_ISRC
:
2496 transferByteCount
= sizeof(SUB_Q_TRACK_ISRC
);
2500 cdb
->SUBCHANNEL
.AllocationLength
[0] = (UCHAR
) (transferByteCount
>> 8);
2501 cdb
->SUBCHANNEL
.AllocationLength
[1] = (UCHAR
) (transferByteCount
& 0xFF);
2502 cdb
->SUBCHANNEL
.OperationCode
= SCSIOP_READ_SUB_CHANNEL
;
2503 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2504 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
2505 srb
->DataTransferLength
= transferByteCount
;
2506 srb
->CdbLength
= 10;
2507 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2509 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2514 case IOCTL_CDROM_PAUSE_AUDIO
: {
2516 cdb
->PAUSE_RESUME
.OperationCode
= SCSIOP_PAUSE_RESUME
;
2517 cdb
->PAUSE_RESUME
.Action
= CDB_AUDIO_PAUSE
;
2519 srb
->CdbLength
= 10;
2520 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2521 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2522 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_NO_DATA_TRANSFER
);
2524 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2528 case IOCTL_CDROM_RESUME_AUDIO
: {
2530 cdb
->PAUSE_RESUME
.OperationCode
= SCSIOP_PAUSE_RESUME
;
2531 cdb
->PAUSE_RESUME
.Action
= CDB_AUDIO_RESUME
;
2533 srb
->CdbLength
= 10;
2534 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2535 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2536 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_NO_DATA_TRANSFER
);
2538 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2542 case IOCTL_CDROM_SEEK_AUDIO_MSF
: {
2544 PCDROM_SEEK_AUDIO_MSF inputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
2545 ULONG logicalBlockAddress
;
2547 logicalBlockAddress
= MSF_TO_LBA(inputBuffer
->M
, inputBuffer
->S
, inputBuffer
->F
);
2549 cdb
->SEEK
.OperationCode
= SCSIOP_SEEK
;
2550 cdb
->SEEK
.LogicalBlockAddress
[0] = ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte3
;
2551 cdb
->SEEK
.LogicalBlockAddress
[1] = ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte2
;
2552 cdb
->SEEK
.LogicalBlockAddress
[2] = ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte1
;
2553 cdb
->SEEK
.LogicalBlockAddress
[3] = ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte0
;
2555 srb
->CdbLength
= 10;
2556 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2557 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2558 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_NO_DATA_TRANSFER
);
2560 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2565 case IOCTL_CDROM_STOP_AUDIO
: {
2567 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
2568 cdb
->START_STOP
.Immediate
= 1;
2569 cdb
->START_STOP
.Start
= 0;
2570 cdb
->START_STOP
.LoadEject
= 0;
2573 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2575 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2576 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_NO_DATA_TRANSFER
);
2578 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2582 case IOCTL_CDROM_GET_CONTROL
: {
2584 // Allocate buffer for volume control information.
2587 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
2591 Irp
->IoStatus
.Information
= 0;
2592 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2593 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2594 ExFreePool(senseBuffer
);
2597 IoStartNextPacket(DeviceObject
, FALSE
);
2602 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2608 if (!irp2
->MdlAddress
) {
2609 Irp
->IoStatus
.Information
= 0;
2610 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2611 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2612 ExFreePool(senseBuffer
);
2614 ExFreePool(dataBuffer
);
2616 IoStartNextPacket(DeviceObject
, FALSE
);
2624 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2625 srb
->DataBuffer
= dataBuffer
;
2627 RtlZeroMemory(dataBuffer
, MODE_DATA_SIZE
);
2630 // Setup for either 6 or 10 byte CDBs.
2635 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
2636 cdb
->MODE_SENSE
.PageCode
= CDROM_AUDIO_CONTROL_PAGE
;
2637 cdb
->MODE_SENSE
.AllocationLength
= MODE_DATA_SIZE
;
2640 // Disable block descriptors.
2643 cdb
->MODE_SENSE
.Dbd
= TRUE
;
2648 cdb
->MODE_SENSE10
.OperationCode
= SCSIOP_MODE_SENSE10
;
2649 cdb
->MODE_SENSE10
.PageCode
= CDROM_AUDIO_CONTROL_PAGE
;
2650 cdb
->MODE_SENSE10
.AllocationLength
[0] = (UCHAR
)(MODE_DATA_SIZE
>> 8);
2651 cdb
->MODE_SENSE10
.AllocationLength
[1] = (UCHAR
)(MODE_DATA_SIZE
& 0xFF);
2654 // Disable block descriptors.
2657 cdb
->MODE_SENSE10
.Dbd
= TRUE
;
2659 srb
->CdbLength
= 10;
2662 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2663 srb
->DataTransferLength
= MODE_DATA_SIZE
;
2664 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2665 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
2667 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2672 case IOCTL_CDROM_GET_VOLUME
:
2673 case IOCTL_CDROM_SET_VOLUME
: {
2675 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
2679 Irp
->IoStatus
.Information
= 0;
2680 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2681 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2682 ExFreePool(senseBuffer
);
2685 IoStartNextPacket(DeviceObject
, FALSE
);
2689 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2695 if (!irp2
->MdlAddress
) {
2696 Irp
->IoStatus
.Information
= 0;
2697 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2698 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2699 ExFreePool(senseBuffer
);
2701 ExFreePool(dataBuffer
);
2703 IoStartNextPacket(DeviceObject
, FALSE
);
2711 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2712 srb
->DataBuffer
= dataBuffer
;
2714 RtlZeroMemory(dataBuffer
, MODE_DATA_SIZE
);
2718 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
2719 cdb
->MODE_SENSE
.PageCode
= CDROM_AUDIO_CONTROL_PAGE
;
2720 cdb
->MODE_SENSE
.AllocationLength
= MODE_DATA_SIZE
;
2726 cdb
->MODE_SENSE10
.OperationCode
= SCSIOP_MODE_SENSE10
;
2727 cdb
->MODE_SENSE10
.PageCode
= CDROM_AUDIO_CONTROL_PAGE
;
2728 cdb
->MODE_SENSE10
.AllocationLength
[0] = (UCHAR
)(MODE_DATA_SIZE
>> 8);
2729 cdb
->MODE_SENSE10
.AllocationLength
[1] = (UCHAR
)(MODE_DATA_SIZE
& 0xFF);
2731 srb
->CdbLength
= 10;
2734 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2735 srb
->DataTransferLength
= MODE_DATA_SIZE
;
2736 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2737 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
2739 if (currentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_SET_VOLUME
) {
2742 // Setup a different completion routine as the mode sense data is needed in order
2743 // to send the mode select.
2746 IoSetCompletionRoutine(irp2
,
2747 CdRomSetVolumeIntermediateCompletion
,
2755 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2763 // Just complete the request - CdRomClassIoctlCompletion will take
2764 // care of it for us
2767 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2768 ExFreePool(senseBuffer
);
2777 // If a read or an unhandled IRP_MJ_XX, end up here. The unhandled IRP_MJ's
2778 // are expected and composed of AutoRun Irps, at present.
2781 IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
2788 ScsiCdRomReadVerification(
2789 IN PDEVICE_OBJECT DeviceObject
,
2795 Routine Description:
2797 This is the entry called by the I/O system for read requests.
2798 It builds the SRB and sends it to the port driver.
2802 DeviceObject - the system object for the device.
2812 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2813 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
2814 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
2815 LARGE_INTEGER startingOffset
= currentIrpStack
->Parameters
.Read
.ByteOffset
;
2818 // If the cd is playing music then reject this request.
2821 if (PLAY_ACTIVE(deviceExtension
)) {
2822 Irp
->IoStatus
.Status
= STATUS_DEVICE_BUSY
;
2823 return STATUS_DEVICE_BUSY
;
2827 // Verify parameters of this request.
2828 // Check that ending sector is on disc and
2829 // that number of bytes to transfer is a multiple of
2833 startingOffset
.QuadPart
= currentIrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+
2836 if (!deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
) {
2837 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= 2048;
2840 if ((startingOffset
.QuadPart
> deviceExtension
->PartitionLength
.QuadPart
) ||
2841 (transferByteCount
& (deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
- 1))) {
2843 DebugPrint((1,"ScsiCdRomRead: Invalid I/O parameters\n"));
2844 DebugPrint((1, "\toffset %x:%x, Length %x:%x\n",
2845 startingOffset
.u
.HighPart
,
2846 startingOffset
.u
.LowPart
,
2847 deviceExtension
->PartitionLength
.u
.HighPart
,
2848 deviceExtension
->PartitionLength
.u
.LowPart
));
2849 DebugPrint((1, "\tbps %x\n", deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
));
2852 // Fail request with status of invalid parameters.
2855 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
2857 return STATUS_INVALID_PARAMETER
;
2861 return STATUS_SUCCESS
;
2863 } // end ScsiCdRomReadVerification()
2868 CdRomDeviceControlCompletion(
2869 IN PDEVICE_OBJECT DeviceObject
,
2874 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2875 PDEVICE_EXTENSION physicalExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
2876 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
2877 PCDROM_DATA cdData
= (PCDROM_DATA
)(deviceExtension
+ 1);
2878 BOOLEAN use6Byte
= cdData
->XAFlags
& XA_USE_6_BYTE
;
2879 PIO_STACK_LOCATION realIrpStack
;
2880 PIO_STACK_LOCATION realIrpNextStack
;
2881 PSCSI_REQUEST_BLOCK srb
= Context
;
2882 PIRP realIrp
= NULL
;
2887 // Extract the 'real' irp from the irpstack.
2890 realIrp
= (PIRP
) irpStack
->Parameters
.Others
.Argument2
;
2891 realIrpStack
= IoGetCurrentIrpStackLocation(realIrp
);
2892 realIrpNextStack
= IoGetNextIrpStackLocation(realIrp
);
2895 // Check SRB status for success of completing request.
2898 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
2901 "CdRomDeviceControlCompletion: Irp %lx, Srb %lx Real Irp %lx Status %lx\n",
2908 // Release the queue if it is frozen.
2911 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
2912 DebugPrint((2, "CdRomDeviceControlCompletion: Releasing Queue\n"));
2913 ScsiClassReleaseQueue(DeviceObject
);
2917 retry
= ScsiClassInterpretSenseInfo(DeviceObject
,
2919 irpStack
->MajorFunction
,
2920 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
,
2921 MAXIMUM_RETRIES
- ((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
),
2924 DebugPrint((2, "CdRomDeviceControlCompletion: IRP will %sbe retried\n",
2925 (retry
? "" : "not ")));
2928 // Some of the Device Controls need special cases on non-Success status's.
2931 if (realIrpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
) {
2932 if ((realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_GET_LAST_SESSION
) ||
2933 (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_READ_TOC
) ||
2934 (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_GET_CONTROL
) ||
2935 (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_GET_VOLUME
)) {
2937 if (status
== STATUS_DATA_OVERRUN
) {
2938 status
= STATUS_SUCCESS
;
2943 if (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_READ_Q_CHANNEL
) {
2944 PLAY_ACTIVE(deviceExtension
) = FALSE
;
2949 // If the status is verified required and the this request
2950 // should bypass verify required then retry the request.
2953 if (realIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
2954 status
== STATUS_VERIFY_REQUIRED
) {
2956 if (((realIrpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
) ||
2957 (realIrpStack
->MajorFunction
== IRP_MJ_INTERNAL_DEVICE_CONTROL
)) &&
2958 (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_CHECK_VERIFY
)) {
2960 ExFreePool(srb
->SenseInfoBuffer
);
2961 if (srb
->DataBuffer
) {
2962 ExFreePool(srb
->DataBuffer
);
2965 if (Irp
->MdlAddress
) {
2966 IoFreeMdl(Irp
->MdlAddress
);
2972 // Update the geometry information, as the media could have changed.
2973 // The completion routine for this will complete the real irp and start
2977 status
= CdRomUpdateCapacity(deviceExtension
,realIrp
, NULL
);
2978 DebugPrint((2, "CdRomDeviceControlCompletion: [%lx] CdRomUpdateCapacity completed with status %lx\n", realIrp
, status
));
2979 ASSERT(status
== STATUS_PENDING
);
2981 return STATUS_MORE_PROCESSING_REQUIRED
;
2985 status
= STATUS_IO_DEVICE_ERROR
;
2991 if (retry
&& (realIrpNextStack
->Parameters
.Others
.Argument1
= (PVOID
)((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
-1))) {
2994 if (((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
)) {
3000 DebugPrint((1, "Retry request %lx - Calling StartIo\n", Irp
));
3003 ExFreePool(srb
->SenseInfoBuffer
);
3004 if (srb
->DataBuffer
) {
3005 ExFreePool(srb
->DataBuffer
);
3008 if (Irp
->MdlAddress
) {
3009 IoFreeMdl(Irp
->MdlAddress
);
3015 // Call StartIo directly since IoStartNextPacket hasn't been called,
3016 // the serialisation is still intact.
3019 ScsiCdRomStartIo(DeviceObject
, realIrp
);
3020 return STATUS_MORE_PROCESSING_REQUIRED
;
3025 // Exhausted retries. Fall through and complete the request with the appropriate status.
3032 // Set status for successful request.
3035 status
= STATUS_SUCCESS
;
3038 if (NT_SUCCESS(status
)) {
3040 switch (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
) {
3042 case IOCTL_DISK_GET_LENGTH_INFO
: {
3044 PREAD_CAPACITY_DATA readCapacityBuffer
= srb
->DataBuffer
;
3051 // Swizzle bytes from Read Capacity and translate into
3052 // the necessary geometry information in the device extension.
3055 tmp
= readCapacityBuffer
->BytesPerBlock
;
3056 ((PFOUR_BYTE
)&bps
)->Byte0
= ((PFOUR_BYTE
)&tmp
)->Byte3
;
3057 ((PFOUR_BYTE
)&bps
)->Byte1
= ((PFOUR_BYTE
)&tmp
)->Byte2
;
3058 ((PFOUR_BYTE
)&bps
)->Byte2
= ((PFOUR_BYTE
)&tmp
)->Byte1
;
3059 ((PFOUR_BYTE
)&bps
)->Byte3
= ((PFOUR_BYTE
)&tmp
)->Byte0
;
3062 // Insure that bps is a power of 2.
3063 // This corrects a problem with the HP 4020i CDR where it
3064 // returns an incorrect number for bytes per sector.
3070 lastBit
= (ULONG
) -1;
3078 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= bps
;
3081 "CdRomDeviceControlCompletion: Calculated bps %#x\n",
3082 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
));
3085 // Copy last sector in reverse byte order.
3088 tmp
= readCapacityBuffer
->LogicalBlockAddress
;
3089 ((PFOUR_BYTE
)&lastSector
)->Byte0
= ((PFOUR_BYTE
)&tmp
)->Byte3
;
3090 ((PFOUR_BYTE
)&lastSector
)->Byte1
= ((PFOUR_BYTE
)&tmp
)->Byte2
;
3091 ((PFOUR_BYTE
)&lastSector
)->Byte2
= ((PFOUR_BYTE
)&tmp
)->Byte1
;
3092 ((PFOUR_BYTE
)&lastSector
)->Byte3
= ((PFOUR_BYTE
)&tmp
)->Byte0
;
3095 // Calculate sector to byte shift.
3098 WHICH_BIT(bps
, deviceExtension
->SectorShift
);
3100 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Sector size is %d\n",
3101 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
));
3103 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Number of Sectors is %d\n",
3107 // Calculate media capacity in bytes.
3110 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(lastSector
+ 1);
3113 // Calculate number of cylinders.
3116 deviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
= (LONGLONG
)((lastSector
+ 1)/(32 * 64));
3118 deviceExtension
->PartitionLength
.QuadPart
=
3119 (deviceExtension
->PartitionLength
.QuadPart
<< deviceExtension
->SectorShift
);
3121 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
3124 // This device supports removable media.
3127 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= RemovableMedia
;
3132 // Assume media type is fixed disk.
3135 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= FixedMedia
;
3139 // Assume sectors per track are 32;
3142 deviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
= 32;
3145 // Assume tracks per cylinder (number of heads) is 64.
3148 deviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
= 64;
3151 // Copy the device extension's geometry info into the user buffer.
3154 RtlMoveMemory(realIrp
->AssociatedIrp
.SystemBuffer
,
3155 &deviceExtension
->PartitionLength
,
3156 sizeof(GET_LENGTH_INFORMATION
));
3159 // update information field.
3162 realIrp
->IoStatus
.Information
= sizeof(DISK_GEOMETRY
);
3166 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
3167 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
: {
3169 PREAD_CAPACITY_DATA readCapacityBuffer
= srb
->DataBuffer
;
3176 // Swizzle bytes from Read Capacity and translate into
3177 // the necessary geometry information in the device extension.
3180 tmp
= readCapacityBuffer
->BytesPerBlock
;
3181 ((PFOUR_BYTE
)&bps
)->Byte0
= ((PFOUR_BYTE
)&tmp
)->Byte3
;
3182 ((PFOUR_BYTE
)&bps
)->Byte1
= ((PFOUR_BYTE
)&tmp
)->Byte2
;
3183 ((PFOUR_BYTE
)&bps
)->Byte2
= ((PFOUR_BYTE
)&tmp
)->Byte1
;
3184 ((PFOUR_BYTE
)&bps
)->Byte3
= ((PFOUR_BYTE
)&tmp
)->Byte0
;
3187 // Insure that bps is a power of 2.
3188 // This corrects a problem with the HP 4020i CDR where it
3189 // returns an incorrect number for bytes per sector.
3195 lastBit
= (ULONG
) -1;
3203 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= bps
;
3206 "CdRomDeviceControlCompletion: Calculated bps %#x\n",
3207 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
));
3210 // Copy last sector in reverse byte order.
3213 tmp
= readCapacityBuffer
->LogicalBlockAddress
;
3214 ((PFOUR_BYTE
)&lastSector
)->Byte0
= ((PFOUR_BYTE
)&tmp
)->Byte3
;
3215 ((PFOUR_BYTE
)&lastSector
)->Byte1
= ((PFOUR_BYTE
)&tmp
)->Byte2
;
3216 ((PFOUR_BYTE
)&lastSector
)->Byte2
= ((PFOUR_BYTE
)&tmp
)->Byte1
;
3217 ((PFOUR_BYTE
)&lastSector
)->Byte3
= ((PFOUR_BYTE
)&tmp
)->Byte0
;
3220 // Calculate sector to byte shift.
3223 WHICH_BIT(bps
, deviceExtension
->SectorShift
);
3225 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Sector size is %d\n",
3226 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
));
3228 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Number of Sectors is %d\n",
3232 // Calculate media capacity in bytes.
3235 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(lastSector
+ 1);
3238 // Calculate number of cylinders.
3241 deviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
= (LONGLONG
)((lastSector
+ 1)/(32 * 64));
3243 deviceExtension
->PartitionLength
.QuadPart
=
3244 (deviceExtension
->PartitionLength
.QuadPart
<< deviceExtension
->SectorShift
);
3246 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
3249 // This device supports removable media.
3252 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= RemovableMedia
;
3257 // Assume media type is fixed disk.
3260 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= FixedMedia
;
3264 // Assume sectors per track are 32;
3267 deviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
= 32;
3270 // Assume tracks per cylinder (number of heads) is 64.
3273 deviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
= 64;
3276 // Copy the device extension's geometry info into the user buffer.
3279 RtlMoveMemory(realIrp
->AssociatedIrp
.SystemBuffer
,
3280 deviceExtension
->DiskGeometry
,
3281 sizeof(DISK_GEOMETRY
));
3284 // update information field.
3287 realIrp
->IoStatus
.Information
= sizeof(DISK_GEOMETRY
);
3291 case IOCTL_CDROM_CHECK_VERIFY
:
3293 if((realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_CHECK_VERIFY
) &&
3294 (realIrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
)) {
3296 *((PULONG
)realIrp
->AssociatedIrp
.SystemBuffer
) =
3297 physicalExtension
->MediaChangeCount
;
3298 realIrp
->IoStatus
.Information
= sizeof(ULONG
);
3300 realIrp
->IoStatus
.Information
= 0;
3303 DebugPrint((2, "CdRomDeviceControlCompletion: [%lx] completing CHECK_VERIFY buddy irp %lx\n", realIrp
, Irp
));
3306 case IOCTL_CDROM_GET_LAST_SESSION
:
3307 case IOCTL_CDROM_READ_TOC
: {
3309 PCDROM_TOC toc
= srb
->DataBuffer
;
3312 // Copy the device extension's geometry info into the user buffer.
3315 RtlMoveMemory(realIrp
->AssociatedIrp
.SystemBuffer
,
3317 srb
->DataTransferLength
);
3320 // update information field.
3323 realIrp
->IoStatus
.Information
= srb
->DataTransferLength
;
3327 case IOCTL_CDROM_PLAY_AUDIO_MSF
:
3329 PLAY_ACTIVE(deviceExtension
) = TRUE
;
3333 case IOCTL_CDROM_READ_Q_CHANNEL
: {
3335 PSUB_Q_CHANNEL_DATA userChannelData
= realIrp
->AssociatedIrp
.SystemBuffer
;
3337 PCDROM_SUB_Q_DATA_FORMAT inputBuffer
= realIrp
->AssociatedIrp
.SystemBuffer
;
3339 PSUB_Q_CHANNEL_DATA subQPtr
= srb
->DataBuffer
;
3342 switch( inputBuffer
->Format
) {
3344 case IOCTL_CDROM_CURRENT_POSITION
:
3345 DebugPrint((2,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr
->CurrentPosition
.Header
.AudioStatus
));
3346 DebugPrint((2,"CdRomDeviceControlCompletion: ADR = 0x%x\n", subQPtr
->CurrentPosition
.ADR
));
3347 DebugPrint((2,"CdRomDeviceControlCompletion: Control = 0x%x\n", subQPtr
->CurrentPosition
.Control
));
3348 DebugPrint((2,"CdRomDeviceControlCompletion: Track = %u\n", subQPtr
->CurrentPosition
.TrackNumber
));
3349 DebugPrint((2,"CdRomDeviceControlCompletion: Index = %u\n", subQPtr
->CurrentPosition
.IndexNumber
));
3350 DebugPrint((2,"CdRomDeviceControlCompletion: Absolute Address = %x\n", *((PULONG
)subQPtr
->CurrentPosition
.AbsoluteAddress
) ));
3351 DebugPrint((2,"CdRomDeviceControlCompletion: Relative Address = %x\n", *((PULONG
)subQPtr
->CurrentPosition
.TrackRelativeAddress
) ));
3354 case IOCTL_CDROM_MEDIA_CATALOG
:
3355 DebugPrint((2,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr
->MediaCatalog
.Header
.AudioStatus
));
3356 DebugPrint((2,"CdRomDeviceControlCompletion: Mcval is %u\n", subQPtr
->MediaCatalog
.Mcval
));
3359 case IOCTL_CDROM_TRACK_ISRC
:
3360 DebugPrint((2,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr
->TrackIsrc
.Header
.AudioStatus
));
3361 DebugPrint((2,"CdRomDeviceControlCompletion: Tcval is %u\n", subQPtr
->TrackIsrc
.Tcval
));
3368 // Update the play active status.
3371 if (subQPtr
->CurrentPosition
.Header
.AudioStatus
== AUDIO_STATUS_IN_PROGRESS
) {
3373 PLAY_ACTIVE(deviceExtension
) = TRUE
;
3377 PLAY_ACTIVE(deviceExtension
) = FALSE
;
3382 // Check if output buffer is large enough to contain
3386 if (realIrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
3387 srb
->DataTransferLength
) {
3389 srb
->DataTransferLength
=
3390 realIrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
3394 // Copy our buffer into users.
3397 RtlMoveMemory(userChannelData
,
3399 srb
->DataTransferLength
);
3401 realIrp
->IoStatus
.Information
= srb
->DataTransferLength
;
3405 case IOCTL_CDROM_PAUSE_AUDIO
:
3407 PLAY_ACTIVE(deviceExtension
) = FALSE
;
3408 realIrp
->IoStatus
.Information
= 0;
3411 case IOCTL_CDROM_RESUME_AUDIO
:
3413 realIrp
->IoStatus
.Information
= 0;
3416 case IOCTL_CDROM_SEEK_AUDIO_MSF
:
3418 realIrp
->IoStatus
.Information
= 0;
3421 case IOCTL_CDROM_STOP_AUDIO
:
3423 PLAY_ACTIVE(deviceExtension
) = FALSE
;
3425 realIrp
->IoStatus
.Information
= 0;
3428 case IOCTL_CDROM_GET_CONTROL
: {
3430 PCDROM_AUDIO_CONTROL audioControl
= srb
->DataBuffer
;
3431 PAUDIO_OUTPUT audioOutput
;
3432 ULONG bytesTransferred
;
3434 audioOutput
= ScsiClassFindModePage((PCHAR
)audioControl
,
3435 srb
->DataTransferLength
,
3436 CDROM_AUDIO_CONTROL_PAGE
,
3439 // Verify the page is as big as expected.
3442 bytesTransferred
= (PCHAR
) audioOutput
- (PCHAR
) audioControl
+
3443 sizeof(AUDIO_OUTPUT
);
3445 if (audioOutput
!= NULL
&&
3446 srb
->DataTransferLength
>= bytesTransferred
) {
3448 audioControl
->LbaFormat
= audioOutput
->LbaFormat
;
3450 audioControl
->LogicalBlocksPerSecond
=
3451 (audioOutput
->LogicalBlocksPerSecond
[0] << (UCHAR
)8) |
3452 audioOutput
->LogicalBlocksPerSecond
[1];
3454 realIrp
->IoStatus
.Information
= sizeof(CDROM_AUDIO_CONTROL
);
3457 realIrp
->IoStatus
.Information
= 0;
3458 status
= STATUS_INVALID_DEVICE_REQUEST
;
3463 case IOCTL_CDROM_GET_VOLUME
: {
3465 PAUDIO_OUTPUT audioOutput
;
3466 PVOLUME_CONTROL volumeControl
= srb
->DataBuffer
;
3467 ULONG i
,bytesTransferred
;
3469 audioOutput
= ScsiClassFindModePage((PCHAR
)volumeControl
,
3470 srb
->DataTransferLength
,
3471 CDROM_AUDIO_CONTROL_PAGE
,
3475 // Verify the page is as big as expected.
3478 bytesTransferred
= (PCHAR
) audioOutput
- (PCHAR
) volumeControl
+
3479 sizeof(AUDIO_OUTPUT
);
3481 if (audioOutput
!= NULL
&&
3482 srb
->DataTransferLength
>= bytesTransferred
) {
3484 for (i
=0; i
<4; i
++) {
3485 volumeControl
->PortVolume
[i
] =
3486 audioOutput
->PortOutput
[i
].Volume
;
3490 // Set bytes transferred in IRP.
3493 realIrp
->IoStatus
.Information
= sizeof(VOLUME_CONTROL
);
3496 realIrp
->IoStatus
.Information
= 0;
3497 status
= STATUS_INVALID_DEVICE_REQUEST
;
3503 case IOCTL_CDROM_SET_VOLUME
:
3505 realIrp
->IoStatus
.Information
= sizeof(VOLUME_CONTROL
);
3511 realIrp
->IoStatus
.Information
= 0;
3512 status
= STATUS_INVALID_DEVICE_REQUEST
;
3518 // Deallocate srb and sense buffer.
3522 if (srb
->DataBuffer
) {
3523 ExFreePool(srb
->DataBuffer
);
3525 if (srb
->SenseInfoBuffer
) {
3526 ExFreePool(srb
->SenseInfoBuffer
);
3531 if (realIrp
->PendingReturned
) {
3532 IoMarkIrpPending(realIrp
);
3535 if (Irp
->MdlAddress
) {
3536 IoFreeMdl(Irp
->MdlAddress
);
3542 // Set status in completing IRP.
3545 realIrp
->IoStatus
.Status
= status
;
3548 // Set the hard error if necessary.
3551 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
3554 // Store DeviceObject for filesystem, and clear
3555 // in IoStatus.Information field.
3558 DebugPrint((1, "CdRomDeviceCompletion - Setting Hard Error on realIrp %lx\n",
3560 IoSetHardErrorOrVerifyDevice(realIrp
, DeviceObject
);
3561 realIrp
->IoStatus
.Information
= 0;
3564 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
3566 IoStartNextPacket(DeviceObject
, FALSE
);
3568 return STATUS_MORE_PROCESSING_REQUIRED
;
3573 CdRomSetVolumeIntermediateCompletion(
3574 IN PDEVICE_OBJECT DeviceObject
,
3579 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3580 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3581 PCDROM_DATA cdData
= (PCDROM_DATA
)(deviceExtension
+ 1);
3582 BOOLEAN use6Byte
= cdData
->XAFlags
& XA_USE_6_BYTE
;
3583 PIO_STACK_LOCATION realIrpStack
;
3584 PIO_STACK_LOCATION realIrpNextStack
;
3585 PSCSI_REQUEST_BLOCK srb
= Context
;
3586 PIRP realIrp
= NULL
;
3591 // Extract the 'real' irp from the irpstack.
3594 realIrp
= (PIRP
) irpStack
->Parameters
.Others
.Argument2
;
3595 realIrpStack
= IoGetCurrentIrpStackLocation(realIrp
);
3596 realIrpNextStack
= IoGetNextIrpStackLocation(realIrp
);
3599 // Check SRB status for success of completing request.
3602 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
3605 "CdRomSetVolumeIntermediateCompletion: Irp %lx, Srb %lx Real Irp\n",
3611 // Release the queue if it is frozen.
3614 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
3615 ScsiClassReleaseQueue(DeviceObject
);
3619 retry
= ScsiClassInterpretSenseInfo(DeviceObject
,
3621 irpStack
->MajorFunction
,
3622 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
,
3623 MAXIMUM_RETRIES
- ((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
),
3626 if (status
== STATUS_DATA_OVERRUN
) {
3627 status
= STATUS_SUCCESS
;
3632 // If the status is verified required and the this request
3633 // should bypass verify required then retry the request.
3636 if (realIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
3637 status
== STATUS_VERIFY_REQUIRED
) {
3639 status
= STATUS_IO_DEVICE_ERROR
;
3643 if (retry
&& (realIrpNextStack
->Parameters
.Others
.Argument1
= (PVOID
)((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
-1))) {
3645 if (((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
)) {
3651 DebugPrint((1, "Retry request %lx - Calling StartIo\n", Irp
));
3654 ExFreePool(srb
->SenseInfoBuffer
);
3655 ExFreePool(srb
->DataBuffer
);
3657 if (Irp
->MdlAddress
) {
3658 IoFreeMdl(Irp
->MdlAddress
);
3664 // Call StartIo directly since IoStartNextPacket hasn't been called,
3665 // the serialisation is still intact.
3667 ScsiCdRomStartIo(DeviceObject
, realIrp
);
3668 return STATUS_MORE_PROCESSING_REQUIRED
;
3673 // Exhausted retries. Fall through and complete the request with the appropriate status.
3680 // Set status for successful request.
3683 status
= STATUS_SUCCESS
;
3686 if (NT_SUCCESS(status
)) {
3688 PAUDIO_OUTPUT audioInput
= NULL
;
3689 PAUDIO_OUTPUT audioOutput
;
3690 PVOLUME_CONTROL volumeControl
= realIrp
->AssociatedIrp
.SystemBuffer
;
3691 ULONG i
,bytesTransferred
,headerLength
;
3695 audioInput
= ScsiClassFindModePage((PCHAR
)srb
->DataBuffer
,
3696 srb
->DataTransferLength
,
3697 CDROM_AUDIO_CONTROL_PAGE
,
3701 // Check to make sure the mode sense data is valid before we go on
3704 if(audioInput
== NULL
) {
3706 DebugPrint((1, "Mode Sense Page %d not found\n",
3707 CDROM_AUDIO_CONTROL_PAGE
));
3709 realIrp
->IoStatus
.Information
= 0;
3710 realIrp
->IoStatus
.Status
= STATUS_IO_DEVICE_ERROR
;
3711 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
3712 ExFreePool(srb
->SenseInfoBuffer
);
3714 IoFreeMdl(Irp
->MdlAddress
);
3716 return STATUS_MORE_PROCESSING_REQUIRED
;
3720 headerLength
= sizeof(MODE_PARAMETER_HEADER
);
3722 headerLength
= sizeof(MODE_PARAMETER_HEADER10
);
3725 bytesTransferred
= sizeof(AUDIO_OUTPUT
) + headerLength
;
3728 // Allocate a new buffer for the mode select.
3731 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, bytesTransferred
);
3734 realIrp
->IoStatus
.Information
= 0;
3735 realIrp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3736 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
3737 ExFreePool(srb
->SenseInfoBuffer
);
3739 IoFreeMdl(Irp
->MdlAddress
);
3741 return STATUS_MORE_PROCESSING_REQUIRED
;
3744 RtlZeroMemory(dataBuffer
, bytesTransferred
);
3747 // Rebuild the data buffer to include the user requested values.
3750 audioOutput
= (PAUDIO_OUTPUT
) ((PCHAR
) dataBuffer
+ headerLength
);
3752 for (i
=0; i
<4; i
++) {
3753 audioOutput
->PortOutput
[i
].Volume
=
3754 volumeControl
->PortVolume
[i
];
3755 audioOutput
->PortOutput
[i
].ChannelSelection
=
3756 audioInput
->PortOutput
[i
].ChannelSelection
;
3759 audioOutput
->CodePage
= CDROM_AUDIO_CONTROL_PAGE
;
3760 audioOutput
->ParameterLength
= sizeof(AUDIO_OUTPUT
) - 2;
3761 audioOutput
->Immediate
= MODE_SELECT_IMMEDIATE
;
3764 // Free the old data buffer, mdl.
3767 ExFreePool(srb
->DataBuffer
);
3768 IoFreeMdl(Irp
->MdlAddress
);
3774 cdb
= (PCDB
)srb
->Cdb
;
3775 RtlZeroMemory(cdb
, CDB12GENERIC_LENGTH
);
3777 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
3778 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
3779 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_OUT
);
3780 srb
->DataTransferLength
= bytesTransferred
;
3784 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
3785 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
) bytesTransferred
;
3786 cdb
->MODE_SELECT
.PFBit
= 1;
3790 cdb
->MODE_SELECT10
.OperationCode
= SCSIOP_MODE_SELECT10
;
3791 cdb
->MODE_SELECT10
.ParameterListLength
[0] = (UCHAR
) (bytesTransferred
>> 8);
3792 cdb
->MODE_SELECT10
.ParameterListLength
[1] = (UCHAR
) (bytesTransferred
& 0xFF);
3793 cdb
->MODE_SELECT10
.PFBit
= 1;
3794 srb
->CdbLength
= 10;
3801 Irp
->MdlAddress
= IoAllocateMdl(dataBuffer
,
3807 if (!Irp
->MdlAddress
) {
3808 realIrp
->IoStatus
.Information
= 0;
3809 realIrp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3810 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
3811 ExFreePool(srb
->SenseInfoBuffer
);
3813 ExFreePool(dataBuffer
);
3815 return STATUS_MORE_PROCESSING_REQUIRED
;
3819 MmBuildMdlForNonPagedPool(Irp
->MdlAddress
);
3820 srb
->DataBuffer
= dataBuffer
;
3822 irpStack
= IoGetNextIrpStackLocation(Irp
);
3823 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
3824 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
3825 irpStack
->Parameters
.Scsi
.Srb
= srb
;
3828 // reset the irp completion.
3831 IoSetCompletionRoutine(Irp
,
3832 CdRomDeviceControlCompletion
,
3838 // Call the port driver.
3841 IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
3843 return STATUS_MORE_PROCESSING_REQUIRED
;
3847 // Deallocate srb and sense buffer.
3851 if (srb
->DataBuffer
) {
3852 ExFreePool(srb
->DataBuffer
);
3854 if (srb
->SenseInfoBuffer
) {
3855 ExFreePool(srb
->SenseInfoBuffer
);
3860 if (Irp
->PendingReturned
) {
3861 IoMarkIrpPending(Irp
);
3864 if (realIrp
->PendingReturned
) {
3865 IoMarkIrpPending(realIrp
);
3868 if (Irp
->MdlAddress
) {
3869 IoFreeMdl(Irp
->MdlAddress
);
3875 // Set status in completing IRP.
3878 realIrp
->IoStatus
.Status
= status
;
3881 // Set the hard error if necessary.
3884 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
3887 // Store DeviceObject for filesystem, and clear
3888 // in IoStatus.Information field.
3891 IoSetHardErrorOrVerifyDevice(realIrp
, DeviceObject
);
3892 realIrp
->IoStatus
.Information
= 0;
3895 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
3897 IoStartNextPacket(DeviceObject
, FALSE
);
3899 return STATUS_MORE_PROCESSING_REQUIRED
;
3905 CdRomSwitchModeCompletion(
3906 IN PDEVICE_OBJECT DeviceObject
,
3911 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3912 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3913 PCDROM_DATA cdData
= (PCDROM_DATA
)(deviceExtension
+ 1);
3914 PIO_STACK_LOCATION realIrpStack
;
3915 PIO_STACK_LOCATION realIrpNextStack
;
3916 PSCSI_REQUEST_BLOCK srb
= Context
;
3917 PIRP realIrp
= NULL
;
3922 // Extract the 'real' irp from the irpstack.
3925 realIrp
= (PIRP
) irpStack
->Parameters
.Others
.Argument2
;
3926 realIrpStack
= IoGetCurrentIrpStackLocation(realIrp
);
3927 realIrpNextStack
= IoGetNextIrpStackLocation(realIrp
);
3930 // Check SRB status for success of completing request.
3933 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
3936 "CdRomSetVolumeIntermediateCompletion: Irp %lx, Srb %lx Real Irp\n",
3942 // Release the queue if it is frozen.
3945 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
3946 ScsiClassReleaseQueue(DeviceObject
);
3950 retry
= ScsiClassInterpretSenseInfo(DeviceObject
,
3952 irpStack
->MajorFunction
,
3953 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
,
3954 MAXIMUM_RETRIES
- ((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
),
3958 // If the status is verified required and the this request
3959 // should bypass verify required then retry the request.
3962 if (realIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
3963 status
== STATUS_VERIFY_REQUIRED
) {
3965 status
= STATUS_IO_DEVICE_ERROR
;
3969 if (retry
&& (realIrpNextStack
->Parameters
.Others
.Argument1
= (PVOID
)((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
-1))) {
3971 if (((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
)) {
3977 DebugPrint((1, "Retry request %lx - Calling StartIo\n", Irp
));
3980 ExFreePool(srb
->SenseInfoBuffer
);
3981 ExFreePool(srb
->DataBuffer
);
3983 if (Irp
->MdlAddress
) {
3984 IoFreeMdl(Irp
->MdlAddress
);
3990 // Call StartIo directly since IoStartNextPacket hasn't been called,
3991 // the serialisation is still intact.
3994 ScsiCdRomStartIo(DeviceObject
, realIrp
);
3995 return STATUS_MORE_PROCESSING_REQUIRED
;
4000 // Exhausted retries. Fall through and complete the request with the appropriate status.
4006 // Set status for successful request.
4009 status
= STATUS_SUCCESS
;
4012 if (NT_SUCCESS(status
)) {
4014 ULONG sectorSize
, startingSector
, transferByteCount
;
4018 // Update device ext. to show which mode we are currently using.
4021 sectorSize
= cdData
->u1
.BlockDescriptor
.BlockLength
[0] << 16;
4022 sectorSize
|= (cdData
->u1
.BlockDescriptor
.BlockLength
[1] << 8);
4023 sectorSize
|= (cdData
->u1
.BlockDescriptor
.BlockLength
[2]);
4025 cdData
->RawAccess
= (sectorSize
== RAW_SECTOR_SIZE
) ? TRUE
: FALSE
;
4028 // Free the old data buffer, mdl.
4031 ExFreePool(srb
->DataBuffer
);
4032 IoFreeMdl(Irp
->MdlAddress
);
4039 cdb
= (PCDB
)srb
->Cdb
;
4040 RtlZeroMemory(cdb
, CDB12GENERIC_LENGTH
);
4043 if (cdData
->RawAccess
) {
4045 PRAW_READ_INFO rawReadInfo
=
4046 (PRAW_READ_INFO
)realIrpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
4048 ULONG maximumTransferLength
;
4049 ULONG transferPages
;
4052 // Calculate starting offset.
4055 startingSector
= (ULONG
)(rawReadInfo
->DiskOffset
.QuadPart
>> deviceExtension
->SectorShift
);
4056 transferByteCount
= rawReadInfo
->SectorCount
* RAW_SECTOR_SIZE
;
4057 maximumTransferLength
= deviceExtension
->PortCapabilities
->MaximumTransferLength
;
4058 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(realIrp
->MdlAddress
),
4062 // Determine if request is within limits imposed by miniport.
4063 // If the request is larger than the miniport's capabilities, split it.
4066 if (transferByteCount
> maximumTransferLength
||
4067 transferPages
> deviceExtension
->PortCapabilities
->MaximumPhysicalPages
) {
4069 realIrp
->IoStatus
.Information
= 0;
4070 realIrp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
4071 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
4073 ExFreePool(srb
->SenseInfoBuffer
);
4076 IoStartNextPacket(DeviceObject
, FALSE
);
4078 return STATUS_MORE_PROCESSING_REQUIRED
;
4081 srb
->OriginalRequest
= realIrp
;
4082 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
4083 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
4084 srb
->DataTransferLength
= transferByteCount
;
4085 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4086 srb
->CdbLength
= 10;
4087 srb
->DataBuffer
= MmGetMdlVirtualAddress(realIrp
->MdlAddress
);
4089 if (rawReadInfo
->TrackMode
== CDDA
) {
4090 if (cdData
->XAFlags
& PLEXTOR_CDDA
) {
4092 srb
->CdbLength
= 12;
4094 cdb
->PLXTR_READ_CDDA
.LogicalUnitNumber
= deviceExtension
->Lun
;
4095 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
4096 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
4097 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
4098 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
4100 cdb
->PLXTR_READ_CDDA
.TransferBlockByte3
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
4101 cdb
->PLXTR_READ_CDDA
.TransferBlockByte2
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
4102 cdb
->PLXTR_READ_CDDA
.TransferBlockByte1
= 0;
4103 cdb
->PLXTR_READ_CDDA
.TransferBlockByte0
= 0;
4105 cdb
->PLXTR_READ_CDDA
.SubCode
= 0;
4106 cdb
->PLXTR_READ_CDDA
.OperationCode
= 0xD8;
4108 } else if (cdData
->XAFlags
& NEC_CDDA
) {
4110 cdb
->NEC_READ_CDDA
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
4111 cdb
->NEC_READ_CDDA
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
4112 cdb
->NEC_READ_CDDA
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
4113 cdb
->NEC_READ_CDDA
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
4115 cdb
->NEC_READ_CDDA
.TransferBlockByte1
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
4116 cdb
->NEC_READ_CDDA
.TransferBlockByte0
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
4118 cdb
->NEC_READ_CDDA
.OperationCode
= 0xD4;
4121 cdb
->CDB10
.LogicalUnitNumber
= deviceExtension
->Lun
;
4123 cdb
->CDB10
.TransferBlocksMsb
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
4124 cdb
->CDB10
.TransferBlocksLsb
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
4126 cdb
->CDB10
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
4127 cdb
->CDB10
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
4128 cdb
->CDB10
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
4129 cdb
->CDB10
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
4131 cdb
->CDB10
.OperationCode
= SCSIOP_READ
;
4134 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
4137 irpStack
= IoGetNextIrpStackLocation(realIrp
);
4138 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
4139 irpStack
->Parameters
.Scsi
.Srb
= srb
;
4141 if (!(irpStack
->Parameters
.Others
.Argument1
)) {
4144 // Only jam this in if it doesn't exist. The completion routines can
4145 // call StartIo directly in the case of retries and resetting it will
4146 // cause infinite loops.
4149 irpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
4153 // Set up IoCompletion routine address.
4156 IoSetCompletionRoutine(realIrp
,
4164 ULONG maximumTransferLength
= deviceExtension
->PortCapabilities
->MaximumTransferLength
;
4165 ULONG transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(realIrp
->MdlAddress
),
4166 realIrpStack
->Parameters
.Read
.Length
);
4168 // Back to cooked sectors. Build and send a normal read.
4169 // The real work for setting offsets and checking for splitrequests was
4173 if ((realIrpStack
->Parameters
.Read
.Length
> maximumTransferLength
) ||
4174 (transferPages
> deviceExtension
->PortCapabilities
->MaximumPhysicalPages
)) {
4177 // Request needs to be split. Completion of each portion of the request will
4178 // fire off the next portion. The final request will signal Io to send a new request.
4181 ScsiClassSplitRequest(DeviceObject
, realIrp
, maximumTransferLength
);
4182 return STATUS_MORE_PROCESSING_REQUIRED
;
4187 // Build SRB and CDB for this IRP.
4190 ScsiClassBuildRequest(DeviceObject
, realIrp
);
4196 // Call the port driver.
4199 IoCallDriver(deviceExtension
->PortDeviceObject
, realIrp
);
4201 return STATUS_MORE_PROCESSING_REQUIRED
;
4205 // Update device Extension flags to indicate that XA isn't supported.
4208 cdData
->XAFlags
|= XA_NOT_SUPPORTED
;
4211 // Deallocate srb and sense buffer.
4215 if (srb
->DataBuffer
) {
4216 ExFreePool(srb
->DataBuffer
);
4218 if (srb
->SenseInfoBuffer
) {
4219 ExFreePool(srb
->SenseInfoBuffer
);
4224 if (Irp
->PendingReturned
) {
4225 IoMarkIrpPending(Irp
);
4228 if (realIrp
->PendingReturned
) {
4229 IoMarkIrpPending(realIrp
);
4232 if (Irp
->MdlAddress
) {
4233 IoFreeMdl(Irp
->MdlAddress
);
4239 // Set status in completing IRP.
4242 realIrp
->IoStatus
.Status
= status
;
4245 // Set the hard error if necessary.
4248 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
4251 // Store DeviceObject for filesystem, and clear
4252 // in IoStatus.Information field.
4255 IoSetHardErrorOrVerifyDevice(realIrp
, DeviceObject
);
4256 realIrp
->IoStatus
.Information
= 0;
4259 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
4261 IoStartNextPacket(DeviceObject
, FALSE
);
4263 return STATUS_MORE_PROCESSING_REQUIRED
;
4269 IN PDEVICE_OBJECT DeviceObject
,
4276 Routine Description:
4278 This routine executes when the port driver has completed a request.
4279 It looks at the SRB status in the completing SRB and if not success
4280 it checks for valid request sense buffer information. If valid, the
4281 info is used to update status with more precise message of type of
4282 error. This routine deallocates the SRB.
4286 DeviceObject - Supplies the device object which represents the logical
4289 Irp - Supplies the Irp which has completed.
4291 Context - Supplies a pointer to the SRB.
4300 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
4301 PIO_STACK_LOCATION irpNextStack
= IoGetNextIrpStackLocation(Irp
);
4302 PSCSI_REQUEST_BLOCK srb
= Context
;
4307 // Check SRB status for success of completing request.
4310 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
4312 DebugPrint((2,"ScsiClassIoComplete: IRP %lx, SRB %lx\n", Irp
, srb
));
4315 // Release the queue if it is frozen.
4318 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
4319 ScsiClassReleaseQueue(DeviceObject
);
4322 retry
= ScsiClassInterpretSenseInfo(
4325 irpStack
->MajorFunction
,
4326 irpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
? irpStack
->Parameters
.DeviceIoControl
.IoControlCode
: 0,
4327 MAXIMUM_RETRIES
- ((ULONG_PTR
)irpNextStack
->Parameters
.Others
.Argument1
),
4331 // If the status is verified required and the this request
4332 // should bypass verify required then retry the request.
4335 if (irpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
4336 status
== STATUS_VERIFY_REQUIRED
) {
4338 status
= STATUS_IO_DEVICE_ERROR
;
4342 if (retry
&& (irpNextStack
->Parameters
.Others
.Argument1
= (PVOID
)((ULONG_PTR
)irpNextStack
->Parameters
.Others
.Argument1
-1))) {
4344 if (((ULONG_PTR
)irpNextStack
->Parameters
.Others
.Argument1
)) {
4350 DebugPrint((1, "CdRomXACompletion: Retry request %lx - Calling StartIo\n", Irp
));
4353 ExFreePool(srb
->SenseInfoBuffer
);
4354 ExFreePool(srb
->DataBuffer
);
4358 // Call StartIo directly since IoStartNextPacket hasn't been called,
4359 // the serialisation is still intact.
4362 ScsiCdRomStartIo(DeviceObject
, Irp
);
4363 return STATUS_MORE_PROCESSING_REQUIRED
;
4368 // Exhausted retries. Fall through and complete the request with the appropriate status.
4374 // Set status for successful request.
4377 status
= STATUS_SUCCESS
;
4379 } // end if (SRB_STATUS(srb->SrbStatus) ...
4382 // Return SRB to nonpaged pool.
4388 // Set status in completing IRP.
4391 Irp
->IoStatus
.Status
= status
;
4394 // Set the hard error if necessary.
4397 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
4400 // Store DeviceObject for filesystem, and clear
4401 // in IoStatus.Information field.
4404 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
4405 Irp
->IoStatus
.Information
= 0;
4409 // If pending has be returned for this irp then mark the current stack as
4413 if (Irp
->PendingReturned
) {
4414 IoMarkIrpPending(Irp
);
4417 //IoCompleteRequest(Irp, IO_DISK_INCREMENT);
4418 IoStartNextPacket(DeviceObject
, FALSE
);
4426 IN PDEVICE_OBJECT DeviceObject
,
4432 Routine Description:
4434 This is the NT device control handler for CDROMs.
4438 DeviceObject - for this CDROM
4440 Irp - IO Request packet
4449 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
4450 PIO_STACK_LOCATION nextStack
;
4451 PKEVENT deviceControlEvent
;
4452 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4453 PCDROM_DATA cdData
= (PCDROM_DATA
)(deviceExtension
+1);
4454 SCSI_REQUEST_BLOCK srb
;
4465 // Zero the SRB on stack.
4468 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
4470 Irp
->IoStatus
.Information
= 0;
4473 // if this is a class driver ioctl then we need to change the base code
4474 // to IOCTL_CDROM_BASE so that the switch statement can handle it.
4476 // WARNING - currently the scsi class ioctl function codes are between
4477 // 0x200 & 0x300. this routine depends on that fact
4480 ioctlCode
= irpStack
->Parameters
.DeviceIoControl
.IoControlCode
;
4481 baseCode
= ioctlCode
>> 16;
4482 functionCode
= (ioctlCode
& (~0xffffc003)) >> 2;
4484 DebugPrint((1, "CdRomDeviceControl: Ioctl Code = %#08lx, Base Code = %#lx,"
4485 " Function Code = %#lx\n",
4491 if((functionCode
>= 0x200) && (functionCode
<= 0x300)) {
4493 ioctlCode
= (ioctlCode
& 0x0000ffff) | CTL_CODE(IOCTL_CDROM_BASE
, 0, 0, 0);
4495 DebugPrint((1, "CdRomDeviceControl: Class Code - new ioctl code is %#08lx\n",
4498 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= ioctlCode
;
4502 switch (ioctlCode
) {
4504 case IOCTL_CDROM_RAW_READ
: {
4506 LARGE_INTEGER startingOffset
;
4507 ULONG transferBytes
;
4508 PRAW_READ_INFO rawReadInfo
= (PRAW_READ_INFO
)irpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
4509 PUCHAR userData
= (PUCHAR
)Irp
->AssociatedIrp
.SystemBuffer
;
4512 // Ensure that XA reads are supported.
4515 if (cdData
->XAFlags
& XA_NOT_SUPPORTED
) {
4518 "CdRomDeviceControl: XA Reads not supported. Flags (%x)\n",
4521 status
= STATUS_INVALID_DEVICE_REQUEST
;
4526 // Check that ending sector is on disc and buffers are there and of
4530 if (rawReadInfo
== NULL
) {
4533 // Called from user space. Validate the buffers.
4536 rawReadInfo
= (PRAW_READ_INFO
)userData
;
4537 irpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
= (PVOID
)userData
;
4539 if (rawReadInfo
== NULL
) {
4541 DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (No extent info\n"));
4543 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
4545 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4546 return STATUS_INVALID_PARAMETER
;
4549 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
!= sizeof(RAW_READ_INFO
)) {
4551 DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (Invalid info buffer\n"));
4553 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
4555 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4556 return STATUS_INVALID_PARAMETER
;
4560 startingOffset
.QuadPart
= rawReadInfo
->DiskOffset
.QuadPart
;
4561 transferBytes
= rawReadInfo
->SectorCount
* RAW_SECTOR_SIZE
;
4563 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< transferBytes
) {
4565 DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (Bad buffer size)\n"));
4568 // Fail request with status of invalid parameters.
4571 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
4573 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4574 return STATUS_INVALID_PARAMETER
;
4577 if ((startingOffset
.QuadPart
+ transferBytes
) > deviceExtension
->PartitionLength
.QuadPart
) {
4579 DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (Request Out of Bounds)\n"));
4582 // Fail request with status of invalid parameters.
4585 status
= STATUS_INVALID_PARAMETER
;
4589 IoMarkIrpPending(Irp
);
4590 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4592 return STATUS_PENDING
;
4595 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
: {
4597 DebugPrint((2,"CdRomDeviceControl: Get drive geometry\n"));
4599 if ( irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
4600 sizeof( DISK_GEOMETRY
) ) {
4602 status
= STATUS_INFO_LENGTH_MISMATCH
;
4606 IoMarkIrpPending(Irp
);
4607 IoStartPacket(DeviceObject
,Irp
, NULL
,NULL
);
4609 return STATUS_PENDING
;
4612 case IOCTL_CDROM_GET_LAST_SESSION
:
4613 case IOCTL_CDROM_READ_TOC
: {
4616 // If the cd is playing music then reject this request.
4619 if (CdRomIsPlayActive(DeviceObject
)) {
4620 Irp
->IoStatus
.Status
= STATUS_DEVICE_BUSY
;
4621 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4622 return STATUS_DEVICE_BUSY
;
4625 IoMarkIrpPending(Irp
);
4626 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4628 return STATUS_PENDING
;
4631 case IOCTL_CDROM_PLAY_AUDIO_MSF
: {
4637 DebugPrint((2,"CdRomDeviceControl: Play audio MSF\n"));
4639 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
4640 sizeof(CDROM_PLAY_AUDIO_MSF
)) {
4643 // Indicate unsuccessful status.
4646 status
= STATUS_BUFFER_TOO_SMALL
;
4650 IoMarkIrpPending(Irp
);
4651 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4653 return STATUS_PENDING
;
4656 case IOCTL_CDROM_SEEK_AUDIO_MSF
: {
4663 DebugPrint((2,"CdRomDeviceControl: Seek audio MSF\n"));
4665 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
4666 sizeof(CDROM_SEEK_AUDIO_MSF
)) {
4669 // Indicate unsuccessful status.
4672 status
= STATUS_BUFFER_TOO_SMALL
;
4675 IoMarkIrpPending(Irp
);
4676 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4678 return STATUS_PENDING
;
4683 case IOCTL_CDROM_PAUSE_AUDIO
: {
4689 DebugPrint((2, "CdRomDeviceControl: Pause audio\n"));
4691 IoMarkIrpPending(Irp
);
4692 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4694 return STATUS_PENDING
;
4699 case IOCTL_CDROM_RESUME_AUDIO
: {
4705 DebugPrint((2, "CdRomDeviceControl: Resume audio\n"));
4707 IoMarkIrpPending(Irp
);
4708 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4710 return STATUS_PENDING
;
4713 case IOCTL_CDROM_READ_Q_CHANNEL
: {
4715 if(irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
4716 sizeof(CDROM_SUB_Q_DATA_FORMAT
)) {
4718 status
= STATUS_BUFFER_TOO_SMALL
;
4719 Irp
->IoStatus
.Information
= 0;
4723 IoMarkIrpPending(Irp
);
4724 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4726 return STATUS_PENDING
;
4729 case IOCTL_CDROM_GET_CONTROL
: {
4731 DebugPrint((2, "CdRomDeviceControl: Get audio control\n"));
4734 // Verify user buffer is large enough for the data.
4737 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
4738 sizeof(CDROM_AUDIO_CONTROL
)) {
4741 // Indicate unsuccessful status and no data transferred.
4744 status
= STATUS_BUFFER_TOO_SMALL
;
4745 Irp
->IoStatus
.Information
= 0;
4750 IoMarkIrpPending(Irp
);
4751 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4753 return STATUS_PENDING
;
4757 case IOCTL_CDROM_GET_VOLUME
: {
4759 DebugPrint((2, "CdRomDeviceControl: Get volume control\n"));
4762 // Verify user buffer is large enough for data.
4765 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
4766 sizeof(VOLUME_CONTROL
)) {
4769 // Indicate unsuccessful status and no data transferred.
4772 status
= STATUS_BUFFER_TOO_SMALL
;
4773 Irp
->IoStatus
.Information
= 0;
4777 IoMarkIrpPending(Irp
);
4778 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4780 return STATUS_PENDING
;
4784 case IOCTL_CDROM_SET_VOLUME
: {
4786 DebugPrint((2, "CdRomDeviceControl: Set volume control\n"));
4788 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
4789 sizeof(VOLUME_CONTROL
)) {
4792 // Indicate unsuccessful status.
4795 status
= STATUS_BUFFER_TOO_SMALL
;
4799 IoMarkIrpPending(Irp
);
4800 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4802 return STATUS_PENDING
;
4806 case IOCTL_CDROM_STOP_AUDIO
: {
4812 DebugPrint((2, "CdRomDeviceControl: Stop audio\n"));
4814 IoMarkIrpPending(Irp
);
4815 IoStartPacket(DeviceObject
,Irp
, NULL
,NULL
);
4817 return STATUS_PENDING
;
4820 case IOCTL_CDROM_CHECK_VERIFY
: {
4821 DebugPrint((1, "CdRomDeviceControl: [%lx] Check Verify\n", Irp
));
4822 IoMarkIrpPending(Irp
);
4824 if((irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
) &&
4825 (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))) {
4827 DebugPrint((1, "CdRomDeviceControl: Check Verify: media count "
4828 "buffer too small\n"));
4830 status
= STATUS_BUFFER_TOO_SMALL
;
4834 IoStartPacket(DeviceObject
,Irp
, NULL
,NULL
);
4836 return STATUS_PENDING
;
4842 // allocate an event and stuff it into our stack location.
4845 deviceControlEvent
= ExAllocatePool(NonPagedPool
, sizeof(KEVENT
));
4847 if(!deviceControlEvent
) {
4849 status
= STATUS_INSUFFICIENT_RESOURCES
;
4853 PIO_STACK_LOCATION currentStack
;
4855 KeInitializeEvent(deviceControlEvent
, NotificationEvent
, FALSE
);
4857 currentStack
= IoGetCurrentIrpStackLocation(Irp
);
4858 nextStack
= IoGetNextIrpStackLocation(Irp
);
4861 // Copy the stack down a notch
4864 *nextStack
= *currentStack
;
4866 IoSetCompletionRoutine(
4868 CdRomClassIoctlCompletion
,
4875 IoSetNextIrpStackLocation(Irp
);
4877 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4878 Irp
->IoStatus
.Information
= 0;
4881 // Override volume verifies on this stack location so that we
4882 // will be forced through the synchronization. Once this location
4883 // goes away we get the old value back
4886 nextStack
->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
4888 IoMarkIrpPending(Irp
);
4890 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4893 // Wait for CdRomClassIoctlCompletion to set the event. This
4894 // ensures serialization remains intact for these unhandled device
4898 KeWaitForSingleObject(
4905 ExFreePool(deviceControlEvent
);
4907 DebugPrint((2, "CdRomDeviceControl: irp %#08lx synchronized\n", Irp
));
4910 // If an error occured then propagate that back up - we are no longer
4911 // guaranteed synchronization and the upper layers will have to
4914 // If no error occured, call down to the class driver directly
4915 // then start up the next request.
4918 if(Irp
->IoStatus
.Status
== STATUS_SUCCESS
) {
4920 status
= ScsiClassDeviceControl(DeviceObject
, Irp
);
4922 KeRaiseIrql(DISPATCH_LEVEL
, &irql
);
4924 IoStartNextPacket(DeviceObject
, FALSE
);
4935 if (status
== STATUS_VERIFY_REQUIRED
) {
4938 // If the status is verified required and this request
4939 // should bypass verify required then retry the request.
4942 if (irpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
) {
4944 status
= STATUS_IO_DEVICE_ERROR
;
4950 if (IoIsErrorUserInduced(status
)) {
4952 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
4957 // Update IRP with completion status.
4960 Irp
->IoStatus
.Status
= status
;
4963 // Complete the request.
4966 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
4967 DebugPrint((2, "CdRomDeviceControl: Status is %lx\n", status
));
4970 } // end ScsiCdRomDeviceControl()
4975 PDEVICE_OBJECT DeviceObject
,
4976 PINQUIRYDATA InquiryData
,
4977 PIO_SCSI_CAPABILITIES PortCapabilities
4982 Routine Description:
4984 This function checks to see if an SCSI logical unit requires an special
4985 initialization or error processing.
4989 DeviceObject - Supplies the device object to be tested.
4991 InquiryData - Supplies the inquiry data returned by the device of interest.
4993 PortCapabilities - Supplies the capabilities of the device object.
5002 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
5003 PCDROM_DATA cdData
= (PCDROM_DATA
)(deviceExtension
+1);
5006 // Look for a Hitachi CDR-1750. Read-ahead must be disabled in order
5007 // to get this cdrom drive to work on scsi adapters that use PIO.
5010 if ((strncmp((PCHAR
)InquiryData
->VendorId
, "HITACHI CDR-1750S", strlen("HITACHI CDR-1750S")) == 0 ||
5011 strncmp((PCHAR
)InquiryData
->VendorId
, "HITACHI CDR-3650/1650S", strlen("HITACHI CDR-3650/1650S")) == 0)
5012 && PortCapabilities
->AdapterUsesPio
) {
5014 DebugPrint((1, "CdRom ScanForSpecial: Found Hitachi CDR-1750S.\n"));
5017 // Setup an error handler to reinitialize the cd rom after it is reset.
5020 deviceExtension
->ClassError
= HitachProcessError
;
5022 } else if (( RtlCompareMemory( InquiryData
->VendorId
,"FUJITSU", 7 ) == 7 ) &&
5023 (( RtlCompareMemory( InquiryData
->ProductId
,"FMCD-101", 8 ) == 8 ) ||
5024 ( RtlCompareMemory( InquiryData
->ProductId
,"FMCD-102", 8 ) == 8 ))) {
5027 // When Read command is issued to FMCD-101 or FMCD-102 and there is a music
5028 // cd in it. It takes longer time than SCSI_CDROM_TIMEOUT before returning
5032 deviceExtension
->TimeOutValue
= 20;
5034 } else if (( RtlCompareMemory( InquiryData
->VendorId
,"TOSHIBA", 7) == 7) &&
5035 (( RtlCompareMemory( InquiryData
->ProductId
,"CD-ROM XM-34", 12) == 12))) {
5037 SCSI_REQUEST_BLOCK srb
;
5044 // Set the density code and the error handler.
5047 length
= (sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH
);
5049 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
5052 // Build the MODE SENSE CDB.
5056 cdb
= (PCDB
)srb
.Cdb
;
5059 // Set timeout value from device extension.
5062 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
5064 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
5065 cdb
->MODE_SENSE
.PageCode
= 0x1;
5066 cdb
->MODE_SENSE
.AllocationLength
= (UCHAR
)length
;
5068 buffer
= ExAllocatePool(NonPagedPoolCacheAligned
, (sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH
));
5073 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
5079 ((PERROR_RECOVERY_DATA
)buffer
)->BlockDescriptor
.DensityCode
= 0x83;
5080 ((PERROR_RECOVERY_DATA
)buffer
)->Header
.ModeDataLength
= 0x0;
5082 RtlCopyMemory(&cdData
->u1
.Header
, buffer
, sizeof(ERROR_RECOVERY_DATA
));
5084 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
5087 // Build the MODE SENSE CDB.
5091 cdb
= (PCDB
)srb
.Cdb
;
5094 // Set timeout value from device extension.
5097 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
5099 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
5100 cdb
->MODE_SELECT
.PFBit
= 1;
5101 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)length
;
5103 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
5109 if (!NT_SUCCESS(status
)) {
5111 "Cdrom.ScanForSpecial: Setting density code on Toshiba failed [%x]\n",
5115 deviceExtension
->ClassError
= ToshibaProcessError
;
5122 // Determine special CD-DA requirements.
5125 if (RtlCompareMemory( InquiryData
->VendorId
,"PLEXTOR",7) == 7) {
5126 cdData
->XAFlags
|= PLEXTOR_CDDA
;
5127 } else if (RtlCompareMemory ( InquiryData
->VendorId
,"NEC",3) == 3) {
5128 cdData
->XAFlags
|= NEC_CDDA
;
5137 PDEVICE_OBJECT DeviceObject
,
5138 PSCSI_REQUEST_BLOCK Srb
,
5144 Routine Description:
5146 This routine checks the type of error. If the error indicates CD-ROM the
5147 CD-ROM needs to be reinitialized then a Mode sense command is sent to the
5148 device. This command disables read-ahead for the device.
5152 DeviceObject - Supplies a pointer to the device object.
5154 Srb - Supplies a pointer to the failing Srb.
5167 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
5168 PSENSE_DATA senseBuffer
= Srb
->SenseInfoBuffer
;
5169 LARGE_INTEGER largeInt
;
5171 PIO_STACK_LOCATION irpStack
;
5173 PSCSI_REQUEST_BLOCK srb
;
5174 PCOMPLETION_CONTEXT context
;
5178 UNREFERENCED_PARAMETER(Status
);
5179 UNREFERENCED_PARAMETER(Retry
);
5181 largeInt
.QuadPart
= (LONGLONG
) 1;
5184 // Check the status. The initialization command only needs to be sent
5185 // if UNIT ATTENTION is returned.
5188 if (!(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
)) {
5191 // The drive does not require reinitialization.
5198 // Found a bad HITACHI cd-rom. These devices do not work with PIO
5199 // adapters when read-ahead is enabled. Read-ahead is disabled by
5200 // a mode select command. The mode select page code is zero and the
5201 // length is 6 bytes. All of the other bytes should be zero.
5205 if ((senseBuffer
->SenseKey
& 0xf) == SCSI_SENSE_UNIT_ATTENTION
) {
5207 DebugPrint((1, "HitachiProcessError: Reinitializing the CD-ROM.\n"));
5210 // Send the special mode select command to disable read-ahead
5211 // on the CD-ROM reader.
5214 alignment
= DeviceObject
->AlignmentRequirement
?
5215 DeviceObject
->AlignmentRequirement
: 1;
5217 context
= ExAllocatePool(
5219 sizeof(COMPLETION_CONTEXT
) + HITACHI_MODE_DATA_SIZE
+ alignment
5222 if (context
== NULL
) {
5225 // If there is not enough memory to fulfill this request,
5226 // simply return. A subsequent retry will fail and another
5227 // chance to start the unit.
5233 context
->DeviceObject
= DeviceObject
;
5234 srb
= &context
->Srb
;
5236 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
5239 // Write length to SRB.
5242 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
5245 // Set up SCSI bus address.
5248 srb
->PathId
= deviceExtension
->PathId
;
5249 srb
->TargetId
= deviceExtension
->TargetId
;
5250 srb
->Lun
= deviceExtension
->Lun
;
5252 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
5253 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
5256 // Set the transfer length.
5259 srb
->DataTransferLength
= HITACHI_MODE_DATA_SIZE
;
5260 srb
->SrbFlags
= SRB_FLAGS_DATA_OUT
| SRB_FLAGS_DISABLE_AUTOSENSE
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
5263 // The data buffer must be aligned.
5266 srb
->DataBuffer
= (PVOID
) (((ULONG_PTR
) (context
+ 1) + (alignment
- 1)) &
5271 // Build the HITACHI read-ahead mode select CDB.
5275 cdb
= (PCDB
)srb
->Cdb
;
5276 cdb
->MODE_SENSE
.LogicalUnitNumber
= srb
->Lun
;
5277 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SELECT
;
5278 cdb
->MODE_SENSE
.AllocationLength
= HITACHI_MODE_DATA_SIZE
;
5281 // Initialize the mode sense data.
5284 modePage
= srb
->DataBuffer
;
5286 RtlZeroMemory(modePage
, HITACHI_MODE_DATA_SIZE
);
5289 // Set the page length field to 6.
5295 // Build the asynchronous request to be sent to the port driver.
5298 irp
= IoBuildAsynchronousFsdRequest(IRP_MJ_WRITE
,
5301 srb
->DataTransferLength
,
5305 IoSetCompletionRoutine(irp
,
5306 (PIO_COMPLETION_ROUTINE
)ScsiClassAsynchronousCompletion
,
5312 irpStack
= IoGetNextIrpStackLocation(irp
);
5314 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
5316 srb
->OriginalRequest
= irp
;
5319 // Save SRB address in next stack for port driver.
5322 irpStack
->Parameters
.Scsi
.Srb
= (PVOID
)srb
;
5325 // Set up IRP Address.
5328 (VOID
)IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
5335 ToshibaProcessErrorCompletion(
5336 PDEVICE_OBJECT DeviceObject
,
5343 Routine Description:
5345 Completion routine for the ClassError routine to handle older Toshiba units
5346 that require setting the density code.
5350 DeviceObject - Supplies a pointer to the device object.
5352 Irp - Pointer to irp created to set the density code.
5354 Context - Supplies a pointer to the Mode Select Srb.
5359 STATUS_MORE_PROCESSING_REQUIRED
5365 PSCSI_REQUEST_BLOCK srb
= Context
;
5368 // Check for a frozen queue.
5371 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
5374 // Unfreeze the queue getting the device object from the context.
5377 ScsiClassReleaseQueue(DeviceObject
);
5381 // Free all of the allocations.
5384 ExFreePool(srb
->DataBuffer
);
5386 IoFreeMdl(Irp
->MdlAddress
);
5390 // Indicate the I/O system should stop processing the Irp completion.
5393 return STATUS_MORE_PROCESSING_REQUIRED
;
5398 ToshibaProcessError(
5399 PDEVICE_OBJECT DeviceObject
,
5400 PSCSI_REQUEST_BLOCK Srb
,
5407 Routine Description:
5409 This routine checks the type of error. If the error indicates a unit attention,
5410 the density code needs to be set via a Mode select command.
5414 DeviceObject - Supplies a pointer to the device object.
5416 Srb - Supplies a pointer to the failing Srb.
5429 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
5430 PCDROM_DATA cdData
= (PCDROM_DATA
)(deviceExtension
+1);
5431 PSENSE_DATA senseBuffer
= Srb
->SenseInfoBuffer
;
5432 PIO_STACK_LOCATION irpStack
;
5434 PSCSI_REQUEST_BLOCK srb
;
5440 if (!(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
)) {
5445 // The Toshiba's require the density code to be set on power up and media changes.
5448 if ((senseBuffer
->SenseKey
& 0xf) == SCSI_SENSE_UNIT_ATTENTION
) {
5451 irp
= IoAllocateIrp((CCHAR
)(deviceExtension
->DeviceObject
->StackSize
+1),
5458 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
5465 length
= sizeof(ERROR_RECOVERY_DATA
);
5466 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, length
);
5473 irp
->MdlAddress
= IoAllocateMdl(dataBuffer
,
5479 if (!irp
->MdlAddress
) {
5481 ExFreePool(dataBuffer
);
5490 MmBuildMdlForNonPagedPool(irp
->MdlAddress
);
5492 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
5494 srb
->DataBuffer
= dataBuffer
;
5495 cdb
= (PCDB
)srb
->Cdb
;
5501 IoSetNextIrpStackLocation(irp
);
5502 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
5503 irp
->IoStatus
.Information
= 0;
5505 irp
->UserBuffer
= NULL
;
5508 // Save the device object and irp in a private stack location.
5511 irpStack
= IoGetCurrentIrpStackLocation(irp
);
5512 irpStack
->DeviceObject
= deviceExtension
->DeviceObject
;
5515 // Construct the IRP stack for the lower level driver.
5518 irpStack
= IoGetNextIrpStackLocation(irp
);
5519 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
5520 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_OUT
;
5521 irpStack
->Parameters
.Scsi
.Srb
= srb
;
5523 IoSetCompletionRoutine(irp
,
5524 ToshibaProcessErrorCompletion
,
5530 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
5531 srb
->PathId
= deviceExtension
->PathId
;
5532 srb
->TargetId
= deviceExtension
->TargetId
;
5533 srb
->Lun
= deviceExtension
->Lun
;
5534 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
5535 srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
5536 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
5538 srb
->OriginalRequest
= irp
;
5539 srb
->SenseInfoBufferLength
= 0;
5542 // Set the transfer length.
5545 srb
->DataTransferLength
= length
;
5546 srb
->SrbFlags
= SRB_FLAGS_DATA_OUT
| SRB_FLAGS_DISABLE_AUTOSENSE
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
5550 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
5551 cdb
->MODE_SELECT
.PFBit
= 1;
5552 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)length
;
5555 // Copy the Mode page into the databuffer.
5558 RtlCopyMemory(srb
->DataBuffer
, &cdData
->u1
.Header
, length
);
5561 // Set the density code.
5564 ((PERROR_RECOVERY_DATA
)srb
->DataBuffer
)->BlockDescriptor
.DensityCode
= 0x83;
5566 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
5573 IN PDEVICE_OBJECT DeviceObject
5578 Routine Description:
5580 This routine determines if the cd is currently playing music.
5584 DeviceObject - Device object to test.
5588 TRUE if the device is playing music.
5592 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
5594 IO_STATUS_BLOCK ioStatus
;
5597 PSUB_Q_CURRENT_POSITION currentBuffer
;
5599 if (!PLAY_ACTIVE(deviceExtension
)) {
5603 currentBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, sizeof(SUB_Q_CURRENT_POSITION
));
5605 if (currentBuffer
== NULL
) {
5609 ((PCDROM_SUB_Q_DATA_FORMAT
) currentBuffer
)->Format
= IOCTL_CDROM_CURRENT_POSITION
;
5610 ((PCDROM_SUB_Q_DATA_FORMAT
) currentBuffer
)->Track
= 0;
5613 // Create notification event object to be used to signal the
5614 // request completion.
5617 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
5620 // Build the synchronous request to be sent to the port driver
5621 // to perform the request.
5624 irp
= IoBuildDeviceIoControlRequest(IOCTL_CDROM_READ_Q_CHANNEL
,
5625 deviceExtension
->DeviceObject
,
5627 sizeof(CDROM_SUB_Q_DATA_FORMAT
),
5629 sizeof(SUB_Q_CURRENT_POSITION
),
5635 ExFreePool(currentBuffer
);
5640 // Pass request to port driver and wait for request to complete.
5643 status
= IoCallDriver(deviceExtension
->DeviceObject
, irp
);
5645 if (status
== STATUS_PENDING
) {
5646 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
5647 status
= ioStatus
.Status
;
5650 if (!NT_SUCCESS(status
)) {
5651 ExFreePool(currentBuffer
);
5655 ExFreePool(currentBuffer
);
5657 return(PLAY_ACTIVE(deviceExtension
));
5661 IO_COMPLETION_ROUTINE CdRomMediaChangeCompletion
;
5664 CdRomMediaChangeCompletion(
5665 PDEVICE_OBJECT DeviceObject
,
5672 Routine Description:
5674 This routine handles the completion of the test unit ready irps
5675 used to determine if the media has changed. If the media has
5676 changed, this code signals the named event to wake up other
5677 system services that react to media change (aka AutoPlay).
5681 DeviceObject - the object for the completion
5682 Irp - the IRP being completed
5683 Context - the SRB from the IRP
5692 PSCSI_REQUEST_BLOCK srb
= (PSCSI_REQUEST_BLOCK
) Context
;
5693 PIO_STACK_LOCATION cdStack
= IoGetCurrentIrpStackLocation(Irp
);
5694 PIO_STACK_LOCATION irpNextStack
= IoGetNextIrpStackLocation(Irp
);
5695 PDEVICE_EXTENSION deviceExtension
;
5696 PDEVICE_EXTENSION physicalExtension
;
5697 PSENSE_DATA senseBuffer
;
5702 DeviceObject
= cdStack
->DeviceObject
;
5703 ASSERT(DeviceObject
);
5705 deviceExtension
= DeviceObject
->DeviceExtension
;
5706 physicalExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
5707 cddata
= (PCDROM_DATA
)(deviceExtension
+ 1);
5709 ASSERT(cddata
->MediaChangeIrp
== NULL
);
5712 // If the sense data field is valid, look for a media change.
5713 // otherwise this iteration of the polling will just assume nothing
5717 DebugPrint((3, "CdRomMediaChangeHandler: Completing Autorun Irp 0x%lx "
5719 Irp
, deviceExtension
->DeviceNumber
));
5721 if (srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) {
5722 if (srb
->SenseInfoBufferLength
>= FIELD_OFFSET(SENSE_DATA
, CommandSpecificInformation
)) {
5725 // See if this is a media change.
5728 senseBuffer
= srb
->SenseInfoBuffer
;
5729 if ((senseBuffer
->SenseKey
& 0x0f) == SCSI_SENSE_UNIT_ATTENTION
) {
5730 if (senseBuffer
->AdditionalSenseCode
== SCSI_ADSENSE_MEDIUM_CHANGED
) {
5732 DebugPrint((1, "CdRomMediaChangeCompletion: New media inserted "
5733 "into CdRom%d [irp = 0x%lx]\n",
5734 deviceExtension
->DeviceNumber
, Irp
));
5737 // Media change event occurred - signal the named event.
5740 KeSetEvent(deviceExtension
->MediaChangeEvent
,
5744 deviceExtension
->MediaChangeNoMedia
= FALSE
;
5748 if (DeviceObject
->Vpb
->Flags
& VPB_MOUNTED
) {
5751 // Must remember the media changed and force the
5752 // file system to verify on next access
5755 DeviceObject
->Flags
|= DO_VERIFY_VOLUME
;
5758 physicalExtension
->MediaChangeCount
++;
5760 } else if(((senseBuffer
->SenseKey
& 0x0f) == SCSI_SENSE_NOT_READY
)&&
5761 (senseBuffer
->AdditionalSenseCode
== SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
)&&
5762 (!deviceExtension
->MediaChangeNoMedia
)){
5765 // If there was no media in the device then signal the waiters if
5766 // we haven't already done so before.
5769 DebugPrint((1, "CdRomMediaChangeCompletion: No media in device"
5770 "CdRom%d [irp = 0x%lx]\n",
5771 deviceExtension
->DeviceNumber
, Irp
));
5773 KeSetEvent(deviceExtension
->MediaChangeEvent
,
5777 deviceExtension
->MediaChangeNoMedia
= TRUE
;
5781 } else if((srb
->SrbStatus
== SRB_STATUS_SUCCESS
)&&
5782 (deviceExtension
->MediaChangeNoMedia
)) {
5784 // We didn't have any media before and now the requests are succeeding
5785 // we probably missed the Media change somehow. Signal the change
5789 DebugPrint((1, "CdRomMediaChangeCompletion: Request completed normally"
5790 "for CdRom%d which was marked w/NoMedia [irp = 0x%lx]\n",
5791 deviceExtension
->DeviceNumber
, Irp
));
5793 KeSetEvent(deviceExtension
->MediaChangeEvent
,
5797 deviceExtension
->MediaChangeNoMedia
= FALSE
;
5801 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
5802 ScsiClassReleaseQueue(deviceExtension
->DeviceObject
);
5806 // Remember the IRP and SRB for use the next time.
5809 irpNextStack
->Parameters
.Scsi
.Srb
= srb
;
5810 cddata
->MediaChangeIrp
= Irp
;
5812 if (deviceExtension
->ClassError
) {
5818 // Throw away the status and retry values. Just give the error routine a chance
5819 // to do what it needs to.
5822 deviceExtension
->ClassError(DeviceObject
,
5828 IoStartNextPacket(DeviceObject
, FALSE
);
5830 return STATUS_MORE_PROCESSING_REQUIRED
;
5836 IN PDEVICE_OBJECT DeviceObject
,
5842 Routine Description:
5844 This routine handles the once per second timer provided by the
5845 Io subsystem. It is only used when the cdrom device itself is
5846 a candidate for autoplay support. It should never be called if
5847 the cdrom device is a changer device.
5851 DeviceObject - what to check.
5864 PLIST_ENTRY listEntry
;
5866 PIO_STACK_LOCATION irpStack
;
5867 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
5869 cddata
= (PCDROM_DATA
)(deviceExtension
+ 1);
5871 if (cddata
->MediaChange
) {
5872 if (cddata
->MediaChangeIrp
!= NULL
) {
5875 // Media change support is active and the IRP is waiting.
5876 // Decrement the timer.
5877 // There is no MP protection on the timer counter. This
5878 // code is the only code that will manipulate the timer
5879 // and only one instance of it should be running at any
5883 cddata
->MediaChangeCountDown
--;
5886 cddata
->MediaChangeIrpTimeInUse
= 0;
5887 cddata
->MediaChangeIrpLost
= FALSE
;
5890 if (!cddata
->MediaChangeCountDown
) {
5891 PSCSI_REQUEST_BLOCK srb
;
5892 PIO_STACK_LOCATION irpNextStack
;
5899 cddata
->MediaChangeCountDown
= MEDIA_CHANGE_DEFAULT_TIME
;
5902 // Prepare the IRP for the test unit ready
5905 irp
= cddata
->MediaChangeIrp
;
5906 cddata
->MediaChangeIrp
= NULL
;
5908 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
5909 irp
->IoStatus
.Information
= 0;
5911 irp
->UserBuffer
= NULL
;
5914 // If the irp is sent down when the volume needs to be
5915 // verified, CdRomUpdateGeometryCompletion won't complete
5916 // it since it's not associated with a thread. Marking
5917 // it to override the verify causes it always be sent
5918 // to the port driver
5921 irpStack
= IoGetCurrentIrpStackLocation(irp
);
5922 irpStack
->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
5924 irpNextStack
= IoGetNextIrpStackLocation(irp
);
5925 irpNextStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
5926 irpNextStack
->Parameters
.DeviceIoControl
.IoControlCode
=
5927 IOCTL_SCSI_EXECUTE_NONE
;
5930 // Prepare the SRB for execution.
5933 srb
= irpNextStack
->Parameters
.Scsi
.Srb
;
5934 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
5936 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
5937 srb
->PathId
= deviceExtension
->PathId
;
5938 srb
->TargetId
= deviceExtension
->TargetId
;
5939 srb
->Lun
= deviceExtension
->Lun
;
5940 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
5941 srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
|
5942 SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
5943 srb
->DataTransferLength
= 0;
5944 srb
->OriginalRequest
= irp
;
5946 RtlZeroMemory(srb
->SenseInfoBuffer
, SENSE_BUFFER_SIZE
);
5947 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
5949 cdb
= (PCDB
) &srb
->Cdb
[0];
5950 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_TEST_UNIT_READY
;
5951 cdb
->CDB6GENERIC
.LogicalUnitNumber
= srb
->Lun
;
5954 // Setup the IRP to perform a test unit ready.
5957 IoSetCompletionRoutine(irp
,
5958 CdRomMediaChangeCompletion
,
5965 // Issue the request.
5968 IoStartPacket(DeviceObject
, irp
, NULL
, NULL
);
5973 if(cddata
->MediaChangeIrpLost
== FALSE
) {
5974 if(cddata
->MediaChangeIrpTimeInUse
++ >
5975 MEDIA_CHANGE_TIMEOUT_TIME
) {
5977 DebugPrint((0, "CdRom%d: AutoPlay has lost it's irp and "
5978 "doesn't know where to find it. Leave it "
5979 "alone and it'll come home dragging it's "
5980 "stack behind it.\n",
5981 deviceExtension
->DeviceNumber
));
5982 cddata
->MediaChangeIrpLost
= TRUE
;
5991 // Process all generic timer IRPS in the timer list. As IRPs are pulled
5992 // off of the TimerIrpList they must be remembered in the first loop
5993 // if they are not sent to the lower driver. After all items have
5994 // been pulled off the list, it is possible to put the held IRPs back
5995 // into the TimerIrpList.
5999 if (IsListEmpty(&cddata
->TimerIrpList
)) {
6002 listEntry
= ExInterlockedRemoveHeadList(&cddata
->TimerIrpList
,
6003 &cddata
->TimerIrpSpinLock
);
6008 // There is something in the timer list. Pick up the IRP and
6009 // see if it is ready to be submitted.
6012 irp
= CONTAINING_RECORD(listEntry
, IRP
, Tail
.Overlay
.ListEntry
);
6013 irpStack
= IoGetCurrentIrpStackLocation(irp
);
6015 if (irpStack
->Parameters
.Others
.Argument3
) {
6019 // Decrement the countdown timer and put the IRP back in the list.
6022 count
= (ULONG_PTR
) irpStack
->Parameters
.Others
.Argument3
;
6024 irpStack
->Parameters
.Others
.Argument3
= (PVOID
) count
;
6026 ASSERT(irp
->AssociatedIrp
.MasterIrp
== NULL
);
6028 irp
->AssociatedIrp
.MasterIrp
= (PVOID
) heldIrpList
;
6035 // Submit this IRP to the lower driver. This IRP does not
6036 // need to be remembered here. It will be handled again when
6040 DebugPrint((1, "CdRomTickHandler: Reissuing request %lx (thread = %lx)\n", irp
, irp
->Tail
.Overlay
.Thread
));
6043 // feed this to the appropriate port driver
6046 IoCallDriver (deviceExtension
->PortDeviceObject
, irp
);
6051 // Pick up the next IRP from the timer list.
6054 listEntry
= ExInterlockedRemoveHeadList(&cddata
->TimerIrpList
,
6055 &cddata
->TimerIrpSpinLock
);
6059 // Move all held IRPs back onto the timer list.
6062 while (heldIrpList
) {
6065 // Save the single list pointer before queueing this IRP.
6068 nextIrp
= (PIRP
) heldIrpList
->AssociatedIrp
.MasterIrp
;
6069 heldIrpList
->AssociatedIrp
.MasterIrp
= NULL
;
6072 // Return the held IRP to the timer list.
6075 ExInterlockedInsertTailList(&cddata
->TimerIrpList
,
6076 &heldIrpList
->Tail
.Overlay
.ListEntry
,
6077 &cddata
->TimerIrpSpinLock
);
6080 // Continue processing the held IRPs
6083 heldIrpList
= nextIrp
;
6089 CdRomCheckRegistryForMediaChangeValue(
6090 IN PUNICODE_STRING RegistryPath
,
6091 IN ULONG DeviceNumber
6096 Routine Description:
6098 The user must specify that AutoPlay is to run on the platform
6099 by setting the registry value HKEY_LOCAL_MACHINE\System\CurrentControlSet\
6100 Services\Cdrom\Autorun:REG_DWORD:1.
6102 The user can override the global setting to enable or disable Autorun on a
6103 specific cdrom device by setting the key HKEY_LOCAL_MACHINE\System\
6104 CurrentControlSet\Services\Cdrom\Device<N>\Autorun:REG_DWORD to one or zero.
6105 (CURRENTLY UNIMPLEMENTED)
6107 If this registry value does not exist or contains the value zero then
6108 the timer to check for media change does not run.
6112 RegistryPath - pointer to the unicode string inside
6113 ...\CurrentControlSet\Services\Cdrom
6114 DeviceNumber - The number of the device object
6118 TRUE - Autorun is enabled.
6124 #define ITEMS_TO_QUERY 2 /* always 1 greater than what is searched */
6125 PRTL_QUERY_REGISTRY_TABLE parameters
= NULL
;
6133 ANSI_STRING paramNum
;
6135 UNICODE_STRING paramStr
;
6137 UNICODE_STRING paramSuffix
;
6138 UNICODE_STRING paramPath
;
6139 UNICODE_STRING paramDevPath
;
6142 // First append \Parameters to the passed in registry path
6145 RtlInitUnicodeString(¶mStr
, L
"\\Parameters");
6147 RtlInitUnicodeString(¶mPath
, NULL
);
6149 paramPath
.MaximumLength
= RegistryPath
->Length
+
6153 paramPath
.Buffer
= ExAllocatePool(PagedPool
, paramPath
.MaximumLength
);
6155 if(!paramPath
.Buffer
) {
6157 DebugPrint((1,"CdRomCheckRegAP: couldn't allocate paramPath\n"));
6162 RtlZeroMemory(paramPath
.Buffer
, paramPath
.MaximumLength
);
6163 RtlAppendUnicodeToString(¶mPath
, RegistryPath
->Buffer
);
6164 RtlAppendUnicodeToString(¶mPath
, paramStr
.Buffer
);
6166 DebugPrint((2, "CdRomCheckRegAP: paramPath [%d] = %ws\n",
6171 // build a counted ANSI string that contains
6172 // the suffix for the path
6175 sprintf(buf
, "\\Device%lu", DeviceNumber
);
6176 RtlInitAnsiString(¶mNum
, buf
);
6179 // Next convert this into a unicode string
6182 status
= RtlAnsiStringToUnicodeString(¶mSuffix
, ¶mNum
, TRUE
);
6184 if(!NT_SUCCESS(status
)) {
6185 DebugPrint((1,"CdRomCheckRegAP: couldn't convert paramNum to paramSuffix\n"));
6186 ExFreePool(paramPath
.Buffer
);
6190 RtlInitUnicodeString(¶mDevPath
, NULL
);
6193 // now build the device specific path
6196 paramDevPath
.MaximumLength
= paramPath
.Length
+
6197 paramSuffix
.Length
+
6199 paramDevPath
.Buffer
= ExAllocatePool(PagedPool
, paramDevPath
.MaximumLength
);
6201 if(!paramDevPath
.Buffer
) {
6202 RtlFreeUnicodeString(¶mSuffix
);
6203 ExFreePool(paramPath
.Buffer
);
6207 RtlZeroMemory(paramDevPath
.Buffer
, paramDevPath
.MaximumLength
);
6208 RtlAppendUnicodeToString(¶mDevPath
, paramPath
.Buffer
);
6209 RtlAppendUnicodeToString(¶mDevPath
, paramSuffix
.Buffer
);
6211 DebugPrint((2, "CdRomCheckRegAP: paramDevPath [%d] = %ws\n",
6215 parameters
= ExAllocatePool(NonPagedPool
,
6216 sizeof(RTL_QUERY_REGISTRY_TABLE
)*ITEMS_TO_QUERY
);
6221 // Check for the Autorun value.
6224 RtlZeroMemory(parameters
,
6225 (sizeof(RTL_QUERY_REGISTRY_TABLE
)*ITEMS_TO_QUERY
));
6227 parameters
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
6228 parameters
[0].Name
= L
"Autorun";
6229 parameters
[0].EntryContext
= &doRun
;
6230 parameters
[0].DefaultType
= REG_DWORD
;
6231 parameters
[0].DefaultData
= &zero
;
6232 parameters
[0].DefaultLength
= sizeof(ULONG
);
6234 status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
| RTL_REGISTRY_OPTIONAL
,
6235 RegistryPath
->Buffer
,
6240 DebugPrint((2, "CdRomCheckRegAP: cdrom/Autorun flag = %d\n", doRun
));
6242 RtlZeroMemory(parameters
,
6243 (sizeof(RTL_QUERY_REGISTRY_TABLE
)*ITEMS_TO_QUERY
));
6245 parameters
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
6246 parameters
[0].Name
= L
"Autorun";
6247 parameters
[0].EntryContext
= &tmp
;
6248 parameters
[0].DefaultType
= REG_DWORD
;
6249 parameters
[0].DefaultData
= &doRun
;
6250 parameters
[0].DefaultLength
= sizeof(ULONG
);
6252 status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
| RTL_REGISTRY_OPTIONAL
,
6258 DebugPrint((2, "CdRomCheckRegAP: cdrom/parameters/autorun flag = %d\n", tmp
));
6260 RtlZeroMemory(parameters
,
6261 (sizeof(RTL_QUERY_REGISTRY_TABLE
) * ITEMS_TO_QUERY
));
6263 parameters
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
6264 parameters
[0].Name
= L
"Autorun";
6265 parameters
[0].EntryContext
= &doRun
;
6266 parameters
[0].DefaultType
= REG_DWORD
;
6267 parameters
[0].DefaultData
= &tmp
;
6268 parameters
[0].DefaultLength
= sizeof(ULONG
);
6270 status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
| RTL_REGISTRY_OPTIONAL
,
6271 paramDevPath
.Buffer
,
6276 DebugPrint((1, "CdRomCheckRegAP: cdrom/parameters/device%d/autorun flag = %d\n", DeviceNumber
, doRun
));
6278 ExFreePool(parameters
);
6282 ExFreePool(paramPath
.Buffer
);
6283 ExFreePool(paramDevPath
.Buffer
);
6284 RtlFreeUnicodeString(¶mSuffix
);
6286 DebugPrint((1, "CdRomCheckRegAP: Autoplay for device %d is %s\n",
6288 (doRun
? "on" : "off")));
6301 IN PDEVICE_OBJECT DeviceObject
,
6308 Routine Description:
6310 This routine is called by DriverEntry to determine whether a Sanyo 3-CD
6311 changer device is present.
6315 DeviceObject - Supplies the device object for the 'real' device.
6321 TRUE - if an Atapi changer device is found.
6328 PCHAR inquiryBuffer
;
6329 IO_STATUS_BLOCK ioStatus
;
6331 PSCSI_ADAPTER_BUS_INFO adapterInfo
;
6333 PINQUIRYDATA inquiryData
;
6334 PSCSI_INQUIRY_DATA lunInfo
;
6336 inquiryBuffer
= ExAllocatePool(NonPagedPool
, 2048);
6337 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
6338 irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA
,
6351 status
= IoCallDriver(DeviceObject
, irp
);
6353 if (status
== STATUS_PENDING
) {
6354 KeWaitForSingleObject(&event
, Executive
, KernelMode
, FALSE
, NULL
);
6355 status
= ioStatus
.Status
;
6358 if (!NT_SUCCESS(status
)) {
6362 adapterInfo
= (PVOID
) inquiryBuffer
;
6364 for (scsiBus
=0; scsiBus
< (ULONG
)adapterInfo
->NumberOfBuses
; scsiBus
++) {
6367 // Get the SCSI bus scan data for this bus.
6370 lunInfo
= (PVOID
) (inquiryBuffer
+ adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
);
6374 if (lunInfo
->PathId
== PathId
&& lunInfo
->TargetId
== TargetId
) {
6376 inquiryData
= (PVOID
) lunInfo
->InquiryData
;
6378 if (RtlCompareMemory(inquiryData
->VendorId
, "TORiSAN CD-ROM CDR-C", 20) == 20) {
6379 ExFreePool(inquiryBuffer
);
6383 ExFreePool(inquiryBuffer
);
6387 if (!lunInfo
->NextInquiryDataOffset
) {
6391 lunInfo
= (PVOID
) (inquiryBuffer
+ lunInfo
->NextInquiryDataOffset
);
6395 ExFreePool(inquiryBuffer
);
6401 IsThisAnAtapiChanger(
6402 IN PDEVICE_OBJECT DeviceObject
,
6403 OUT PULONG DiscsPresent
6408 Routine Description:
6410 This routine is called by DriverEntry to determine whether an Atapi
6411 changer device is present.
6415 DeviceObject - Supplies the device object for the 'real' device.
6417 DiscsPresent - Supplies a pointer to the number of Discs supported by the changer.
6421 TRUE - if an Atapi changer device is found.
6426 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
6427 PMECHANICAL_STATUS_INFORMATION_HEADER mechanicalStatusBuffer
;
6429 SCSI_REQUEST_BLOCK srb
;
6430 PCDB cdb
= (PCDB
) &srb
.Cdb
[0];
6431 BOOLEAN retVal
= FALSE
;
6436 // Some devices can't handle 12 byte CDB's gracefully
6439 if(deviceExtension
->DeviceFlags
& DEV_NO_12BYTE_CDB
) {
6446 // Build and issue the mechanical status command.
6449 mechanicalStatusBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
6450 sizeof(MECHANICAL_STATUS_INFORMATION_HEADER
));
6452 if (!mechanicalStatusBuffer
) {
6457 // Build and send the Mechanism status CDB.
6460 RtlZeroMemory(&srb
, sizeof(srb
));
6463 srb
.TimeOutValue
= 20;
6465 cdb
->MECH_STATUS
.OperationCode
= SCSIOP_MECHANISM_STATUS
;
6466 cdb
->MECH_STATUS
.AllocationLength
[1] = sizeof(MECHANICAL_STATUS_INFORMATION_HEADER
);
6468 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
6470 mechanicalStatusBuffer
,
6471 sizeof(MECHANICAL_STATUS_INFORMATION_HEADER
),
6475 if (status
== STATUS_SUCCESS
) {
6478 // Indicate number of slots available
6481 *DiscsPresent
= mechanicalStatusBuffer
->NumberAvailableSlots
;
6482 if (*DiscsPresent
> 1) {
6487 // If only one disc, no need for this driver.
6495 // Device doesn't support this command.
6501 ExFreePool(mechanicalStatusBuffer
);
6509 IsThisAMultiLunDevice(
6510 IN PDEVICE_OBJECT DeviceObject
,
6511 IN PDEVICE_OBJECT PortDeviceObject
6515 Routine Description:
6517 This routine is called to determine whether a multi-lun
6522 DeviceObject - Supplies the device object for the 'real' device.
6526 TRUE - if a Multi-lun device is found.
6531 PSCSI_INQUIRY_DATA lunInfo
;
6532 PSCSI_ADAPTER_BUS_INFO adapterInfo
;
6533 PDEVICE_EXTENSION deviceExtension
= (PDEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
6534 PINQUIRYDATA inquiryData
;
6539 status
= ScsiClassGetInquiryData(PortDeviceObject
, (PSCSI_ADAPTER_BUS_INFO
*) &buffer
);
6541 if (!NT_SUCCESS(status
)) {
6542 DebugPrint((1,"IsThisAMultiLunDevice: ScsiClassGetInquiryData failed\n"));
6546 adapterInfo
= (PVOID
) buffer
;
6549 // For each SCSI bus this adapter supports ...
6552 for (scsiBus
=0; scsiBus
< adapterInfo
->NumberOfBuses
; scsiBus
++) {
6555 // Get the SCSI bus scan data for this bus.
6558 lunInfo
= (PVOID
) (buffer
+ adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
);
6560 while (adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
) {
6562 inquiryData
= (PVOID
)lunInfo
->InquiryData
;
6564 if ((lunInfo
->PathId
== deviceExtension
->PathId
) &&
6565 (lunInfo
->TargetId
== deviceExtension
->TargetId
) &&
6566 (inquiryData
->DeviceType
== READ_ONLY_DIRECT_ACCESS_DEVICE
)) {
6568 DebugPrint((1,"IsThisAMultiLunDevice: Vendor string is %.24s\n",
6569 inquiryData
->VendorId
));
6572 // If this device has more than one cdrom-type lun then we
6573 // won't support autoplay on it
6583 // Get next LunInfo.
6586 if (lunInfo
->NextInquiryDataOffset
== 0) {
6590 lunInfo
= (PVOID
) (buffer
+ lunInfo
->NextInquiryDataOffset
);
6599 IO_COMPLETION_ROUTINE CdRomUpdateGeometryCompletion
;
6602 CdRomUpdateGeometryCompletion(
6603 PDEVICE_OBJECT DeviceObject
,
6610 Routine Description:
6612 This routine andles the completion of the test unit ready irps
6613 used to determine if the media has changed. If the media has
6614 changed, this code signals the named event to wake up other
6615 system services that react to media change (aka AutoPlay).
6619 DeviceObject - the object for the completion
6620 Irp - the IRP being completed
6621 Context - the SRB from the IRP
6630 PSCSI_REQUEST_BLOCK srb
= (PSCSI_REQUEST_BLOCK
) Context
;
6631 PREAD_CAPACITY_DATA readCapacityBuffer
;
6632 PDEVICE_EXTENSION deviceExtension
;
6633 PIO_STACK_LOCATION irpStack
;
6636 ULONG_PTR retryCount
;
6642 // Get items saved in the private IRP stack location.
6645 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
6646 retryCount
= (ULONG_PTR
) irpStack
->Parameters
.Others
.Argument1
;
6647 originalIrp
= (PIRP
) irpStack
->Parameters
.Others
.Argument2
;
6649 if (!DeviceObject
) {
6650 DeviceObject
= irpStack
->DeviceObject
;
6652 ASSERT(DeviceObject
);
6654 deviceExtension
= DeviceObject
->DeviceExtension
;
6655 cddata
= (PCDROM_DATA
) (deviceExtension
+ 1);
6656 readCapacityBuffer
= srb
->DataBuffer
;
6658 if ((NT_SUCCESS(Irp
->IoStatus
.Status
)) && (SRB_STATUS(srb
->SrbStatus
) == SRB_STATUS_SUCCESS
)) {
6662 DebugPrint((2, "CdRomUpdateCapacityCompletion: [%lx] successful completion of buddy-irp %lx\n", originalIrp
, Irp
));
6664 // Copy sector size from read capacity buffer to device extension
6665 // in reverse byte order.
6668 from
= (PFOUR_BYTE
) &readCapacityBuffer
->BytesPerBlock
;
6669 to
= (PFOUR_BYTE
) &deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
;
6670 to
->Byte0
= from
->Byte3
;
6671 to
->Byte1
= from
->Byte2
;
6672 to
->Byte2
= from
->Byte1
;
6673 to
->Byte3
= from
->Byte0
;
6676 // Using the new BytesPerBlock, calculate and store the SectorShift.
6679 WHICH_BIT(deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
, deviceExtension
->SectorShift
);
6682 // Copy last sector in reverse byte order.
6685 from
= (PFOUR_BYTE
) &readCapacityBuffer
->LogicalBlockAddress
;
6686 to
= (PFOUR_BYTE
) &lastSector
;
6687 to
->Byte0
= from
->Byte3
;
6688 to
->Byte1
= from
->Byte2
;
6689 to
->Byte2
= from
->Byte1
;
6690 to
->Byte3
= from
->Byte0
;
6691 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(lastSector
+ 1);
6694 // Calculate number of cylinders.
6697 deviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
= (LONGLONG
)((lastSector
+ 1)/(32 * 64));
6698 deviceExtension
->PartitionLength
.QuadPart
=
6699 (deviceExtension
->PartitionLength
.QuadPart
<< deviceExtension
->SectorShift
);
6700 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= RemovableMedia
;
6703 // Assume sectors per track are 32;
6706 deviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
= 32;
6709 // Assume tracks per cylinder (number of heads) is 64.
6712 deviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
= 64;
6716 DebugPrint((1, "CdRomUpdateCapacityCompletion: [%lx] unsuccessful completion of buddy-irp %lx (status - %lx)\n", originalIrp
, Irp
, Irp
->IoStatus
.Status
));
6718 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
6719 ScsiClassReleaseQueue(DeviceObject
);
6722 retry
= ScsiClassInterpretSenseInfo(DeviceObject
,
6733 DebugPrint((1, "CdRomUpdateCapacityCompletion: [%lx] Retrying request %lx .. thread is %lx\n", originalIrp
, Irp
, Irp
->Tail
.Overlay
.Thread
));
6735 // set up a one shot timer to get this process started over
6738 irpStack
->Parameters
.Others
.Argument1
= (PVOID
) retryCount
;
6739 irpStack
->Parameters
.Others
.Argument2
= (PVOID
) originalIrp
;
6740 irpStack
->Parameters
.Others
.Argument3
= (PVOID
) 2;
6743 // Setup the IRP to be submitted again in the timer routine.
6746 irpStack
= IoGetNextIrpStackLocation(Irp
);
6747 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
6748 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
6749 irpStack
->Parameters
.Scsi
.Srb
= srb
;
6750 IoSetCompletionRoutine(Irp
,
6751 CdRomUpdateGeometryCompletion
,
6758 // Set up the SRB for read capacity.
6761 srb
->CdbLength
= 10;
6762 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
6763 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
6765 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
6766 srb
->PathId
= deviceExtension
->PathId
;
6767 srb
->TargetId
= deviceExtension
->TargetId
;
6768 srb
->Lun
= deviceExtension
->Lun
;
6769 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
6770 srb
->SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
6771 srb
->DataTransferLength
= sizeof(READ_CAPACITY_DATA
);
6777 cdb
= (PCDB
) &srb
->Cdb
[0];
6778 cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
6779 cdb
->CDB10
.LogicalUnitNumber
= deviceExtension
->Lun
;
6782 // Requests queued onto this list will be sent to the
6783 // lower level driver during CdRomTickHandler
6786 ExInterlockedInsertHeadList(&cddata
->TimerIrpList
,
6787 &Irp
->Tail
.Overlay
.ListEntry
,
6788 &cddata
->TimerIrpSpinLock
);
6790 return STATUS_MORE_PROCESSING_REQUIRED
;
6794 // This has been bounced for a number of times. Error the
6795 // original request.
6798 originalIrp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
6799 RtlZeroMemory(deviceExtension
->DiskGeometry
, sizeof(DISK_GEOMETRY_EX
));
6800 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= 2048;
6801 deviceExtension
->SectorShift
= 11;
6802 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(0x7fffffff);
6803 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= RemovableMedia
;
6808 // Set up reasonable defaults
6811 RtlZeroMemory(deviceExtension
->DiskGeometry
, sizeof(DISK_GEOMETRY_EX
));
6812 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= 2048;
6813 deviceExtension
->SectorShift
= 11;
6814 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(0x7fffffff);
6815 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= RemovableMedia
;
6820 // Free resources held.
6823 ExFreePool(srb
->SenseInfoBuffer
);
6824 ExFreePool(srb
->DataBuffer
);
6826 if (Irp
->MdlAddress
) {
6827 IoFreeMdl(Irp
->MdlAddress
);
6830 if (originalIrp
->Tail
.Overlay
.Thread
) {
6832 DebugPrint((2, "CdRomUpdateCapacityCompletion: [%lx] completing original IRP\n", originalIrp
));
6833 IoCompleteRequest(originalIrp
, IO_DISK_INCREMENT
);
6836 DebugPrint((1, "CdRomUpdateCapacityCompletion: [%lx] original irp has "
6843 // It's now safe to either start the next request or let the waiting ioctl
6844 // request continue along it's merry way
6847 IoStartNextPacket(DeviceObject
, FALSE
);
6849 return STATUS_MORE_PROCESSING_REQUIRED
;
6854 CdRomUpdateCapacity(
6855 IN PDEVICE_EXTENSION DeviceExtension
,
6856 IN PIRP IrpToComplete
,
6857 IN OPTIONAL PKEVENT IoctlEvent
6862 Routine Description:
6864 This routine updates the capacity of the disk as recorded in the device extension.
6865 It also completes the IRP given with STATUS_VERIFY_REQUIRED. This routine is called
6866 when a media change has occurred and it is necessary to determine the capacity of the
6867 new media prior to the next access.
6871 DeviceExtension - the device to update
6872 IrpToComplete - the request that needs to be completed when done.
6883 PSCSI_REQUEST_BLOCK srb
;
6884 PREAD_CAPACITY_DATA capacityBuffer
;
6885 PIO_STACK_LOCATION irpStack
;
6888 irp
= IoAllocateIrp((CCHAR
)(DeviceExtension
->DeviceObject
->StackSize
+1),
6893 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
6895 capacityBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
6896 sizeof(READ_CAPACITY_DATA
));
6898 if (capacityBuffer
) {
6901 senseBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
6905 irp
->MdlAddress
= IoAllocateMdl(capacityBuffer
,
6906 sizeof(READ_CAPACITY_DATA
),
6911 if (irp
->MdlAddress
) {
6914 // Have all resources. Set up the IRP to send for the capacity.
6917 IoSetNextIrpStackLocation(irp
);
6918 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
6919 irp
->IoStatus
.Information
= 0;
6921 irp
->UserBuffer
= NULL
;
6924 // Save the device object and retry count in a private stack location.
6927 irpStack
= IoGetCurrentIrpStackLocation(irp
);
6928 irpStack
->DeviceObject
= DeviceExtension
->DeviceObject
;
6929 irpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
6930 irpStack
->Parameters
.Others
.Argument2
= (PVOID
) IrpToComplete
;
6933 // Construct the IRP stack for the lower level driver.
6936 irpStack
= IoGetNextIrpStackLocation(irp
);
6937 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
6938 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
6939 irpStack
->Parameters
.Scsi
.Srb
= srb
;
6940 IoSetCompletionRoutine(irp
,
6941 CdRomUpdateGeometryCompletion
,
6950 MmBuildMdlForNonPagedPool(irp
->MdlAddress
);
6954 // Set up the SRB for read capacity.
6957 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
6958 RtlZeroMemory(senseBuffer
, SENSE_BUFFER_SIZE
);
6959 srb
->CdbLength
= 10;
6960 srb
->TimeOutValue
= DeviceExtension
->TimeOutValue
;
6961 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
6963 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
6964 srb
->PathId
= DeviceExtension
->PathId
;
6965 srb
->TargetId
= DeviceExtension
->TargetId
;
6966 srb
->Lun
= DeviceExtension
->Lun
;
6967 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
6968 srb
->SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
6969 srb
->DataBuffer
= capacityBuffer
;
6970 srb
->DataTransferLength
= sizeof(READ_CAPACITY_DATA
);
6971 srb
->OriginalRequest
= irp
;
6972 srb
->SenseInfoBuffer
= senseBuffer
;
6973 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
6979 cdb
= (PCDB
) &srb
->Cdb
[0];
6980 cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
6981 cdb
->CDB10
.LogicalUnitNumber
= DeviceExtension
->Lun
;
6984 // Set the return value in the IRP that will be completed
6985 // upon completion of the read capacity.
6988 IrpToComplete
->IoStatus
.Status
= STATUS_VERIFY_REQUIRED
;
6989 IoMarkIrpPending(IrpToComplete
);
6991 IoCallDriver(DeviceExtension
->PortDeviceObject
, irp
);
6994 // status is not checked because the completion routine for this
6995 // IRP will always get called and it will free the resources.
6998 return STATUS_PENDING
;
7001 ExFreePool(senseBuffer
);
7002 ExFreePool(capacityBuffer
);
7007 ExFreePool(capacityBuffer
);
7020 return STATUS_INSUFFICIENT_RESOURCES
;
7025 CdRomClassIoctlCompletion(
7026 IN PDEVICE_OBJECT DeviceObject
,
7033 Routine Description:
7035 This routine signals the event used by CdRomDeviceControl to synchronize
7036 class driver (and lower level driver) ioctls with cdrom's startio routine.
7037 The irp completion is short-circuited so that CdRomDeviceControl can
7038 reissue it once it wakes up.
7042 DeviceObject - the device object
7043 Irp - the request we are synchronizing
7044 Context - a PKEVENT that we need to signal
7053 PKEVENT syncEvent
= (PKEVENT
) Context
;
7055 DebugPrint((2, "CdRomClassIoctlCompletion: setting event for irp %#08lx\n",
7059 KeSetEvent(syncEvent
, IO_DISK_INCREMENT
, FALSE
);
7061 return STATUS_MORE_PROCESSING_REQUIRED
;