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
);
2143 IoStartNextPacket(DeviceObject
, FALSE
);
2144 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp
, Irp
->IoStatus
.Status
, __LINE__
));
2148 cdb
->READ_CD
.OperationCode
= SCSIOP_READ_CD
;
2150 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
2151 nextIrpStack
->Parameters
.Scsi
.Srb
= srb
;
2153 if (!(nextIrpStack
->Parameters
.Others
.Argument1
)) {
2156 // Only jam this in if it doesn't exist. The completion routines can
2157 // call StartIo directly in the case of retries and resetting it will
2158 // cause infinite loops.
2161 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
2165 // Set up IoCompletion routine address.
2168 IoSetCompletionRoutine(Irp
,
2175 IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
2180 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2184 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
: {
2187 // Issue ReadCapacity to update device extension
2188 // with information for current media.
2192 "CdRomStartIo: Get drive capacity\n"));
2195 // setup remaining srb and cdb parameters.
2198 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2199 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
2200 srb
->DataTransferLength
= sizeof(READ_CAPACITY_DATA
);
2201 srb
->CdbLength
= 10;
2202 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2204 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, sizeof(READ_CAPACITY_DATA
));
2206 Irp
->IoStatus
.Information
= 0;
2207 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2208 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2209 ExFreePool(senseBuffer
);
2212 IoStartNextPacket(DeviceObject
, FALSE
);
2213 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp
, Irp
->IoStatus
.Status
, __LINE__
));
2218 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2219 sizeof(READ_CAPACITY_DATA
),
2224 if (!irp2
->MdlAddress
) {
2225 Irp
->IoStatus
.Information
= 0;
2226 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2227 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2228 ExFreePool(senseBuffer
);
2230 ExFreePool(dataBuffer
);
2232 IoStartNextPacket(DeviceObject
, FALSE
);
2233 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp
, Irp
->IoStatus
.Status
, __LINE__
));
2241 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2243 srb
->DataBuffer
= dataBuffer
;
2244 cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
2246 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2250 case IOCTL_CDROM_CHECK_VERIFY
: {
2253 // Since a test unit ready is about to be performed, reset the timer
2254 // value to decrease the opportunities for it to race with this code.
2257 cdData
->MediaChangeCountDown
= MEDIA_CHANGE_DEFAULT_TIME
;
2260 // Set up the SRB/CDB
2264 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_TEST_UNIT_READY
;
2265 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
* 2;
2266 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2267 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_NO_DATA_TRANSFER
);
2269 DebugPrint((2, "ScsiCdRomStartIo: [%lx] Sending CHECK_VERIFY irp %lx\n", Irp
, irp2
));
2270 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2274 case IOCTL_CDROM_GET_LAST_SESSION
:
2277 // Set format to return first and last session numbers.
2280 cdb
->READ_TOC
.Format
= GET_LAST_SESSION
;
2283 // Fall through to READ TOC code.
2286 case IOCTL_CDROM_READ_TOC
: {
2289 if (currentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_READ_TOC
) {
2292 // Use MSF addressing if not request for session information.
2295 cdb
->READ_TOC
.Msf
= CDB_USE_MSF
;
2299 // Set size of TOC structure.
2303 currentIrpStack
->Parameters
.Read
.Length
>
2304 sizeof(CDROM_TOC
) ? sizeof(CDROM_TOC
):
2305 currentIrpStack
->Parameters
.Read
.Length
;
2307 cdb
->READ_TOC
.AllocationLength
[0] = (UCHAR
) (transferByteCount
>> 8);
2308 cdb
->READ_TOC
.AllocationLength
[1] = (UCHAR
) (transferByteCount
& 0xFF);
2310 cdb
->READ_TOC
.Control
= 0;
2313 // Start at beginning of disc.
2316 cdb
->READ_TOC
.StartingTrack
= 0;
2319 // setup remaining srb and cdb parameters.
2322 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2323 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
2324 srb
->DataTransferLength
= transferByteCount
;
2325 srb
->CdbLength
= 10;
2326 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2328 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, transferByteCount
);
2330 Irp
->IoStatus
.Information
= 0;
2331 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2332 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2333 ExFreePool(senseBuffer
);
2336 IoStartNextPacket(DeviceObject
, FALSE
);
2341 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2347 if (!irp2
->MdlAddress
) {
2348 Irp
->IoStatus
.Information
= 0;
2349 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2350 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2351 ExFreePool(senseBuffer
);
2353 ExFreePool(dataBuffer
);
2355 IoStartNextPacket(DeviceObject
, FALSE
);
2363 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2365 srb
->DataBuffer
= dataBuffer
;
2366 cdb
->READ_TOC
.OperationCode
= SCSIOP_READ_TOC
;
2368 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2373 case IOCTL_CDROM_PLAY_AUDIO_MSF
: {
2375 PCDROM_PLAY_AUDIO_MSF inputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
2378 // Set up the SRB/CDB
2381 srb
->CdbLength
= 10;
2382 cdb
->PLAY_AUDIO_MSF
.OperationCode
= SCSIOP_PLAY_AUDIO_MSF
;
2384 cdb
->PLAY_AUDIO_MSF
.StartingM
= inputBuffer
->StartingM
;
2385 cdb
->PLAY_AUDIO_MSF
.StartingS
= inputBuffer
->StartingS
;
2386 cdb
->PLAY_AUDIO_MSF
.StartingF
= inputBuffer
->StartingF
;
2388 cdb
->PLAY_AUDIO_MSF
.EndingM
= inputBuffer
->EndingM
;
2389 cdb
->PLAY_AUDIO_MSF
.EndingS
= inputBuffer
->EndingS
;
2390 cdb
->PLAY_AUDIO_MSF
.EndingF
= inputBuffer
->EndingF
;
2392 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2393 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2394 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_NO_DATA_TRANSFER
);
2396 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2401 case IOCTL_CDROM_READ_Q_CHANNEL
: {
2403 PCDROM_SUB_Q_DATA_FORMAT inputBuffer
=
2404 Irp
->AssociatedIrp
.SystemBuffer
;
2407 // Allocate buffer for subq channel information.
2410 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
2411 sizeof(SUB_Q_CHANNEL_DATA
));
2414 Irp
->IoStatus
.Information
= 0;
2415 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2416 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2417 ExFreePool(senseBuffer
);
2420 IoStartNextPacket(DeviceObject
, FALSE
);
2425 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2431 if (!irp2
->MdlAddress
) {
2432 Irp
->IoStatus
.Information
= 0;
2433 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2434 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2435 ExFreePool(senseBuffer
);
2437 ExFreePool(dataBuffer
);
2439 IoStartNextPacket(DeviceObject
, FALSE
);
2447 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2449 srb
->DataBuffer
= dataBuffer
;
2452 // Always logical unit 0, but only use MSF addressing
2453 // for IOCTL_CDROM_CURRENT_POSITION
2456 if (inputBuffer
->Format
==IOCTL_CDROM_CURRENT_POSITION
)
2457 cdb
->SUBCHANNEL
.Msf
= CDB_USE_MSF
;
2460 // Return subchannel data
2463 cdb
->SUBCHANNEL
.SubQ
= CDB_SUBCHANNEL_BLOCK
;
2466 // Specify format of informatin to return
2469 cdb
->SUBCHANNEL
.Format
= inputBuffer
->Format
;
2472 // Specify which track to access (only used by Track ISRC reads)
2475 if (inputBuffer
->Format
==IOCTL_CDROM_TRACK_ISRC
) {
2476 cdb
->SUBCHANNEL
.TrackNumber
= inputBuffer
->Track
;
2480 // Set size of channel data -- however, this is dependent on
2481 // what information we are requesting (which Format)
2484 switch( inputBuffer
->Format
) {
2486 case IOCTL_CDROM_CURRENT_POSITION
:
2487 transferByteCount
= sizeof(SUB_Q_CURRENT_POSITION
);
2490 case IOCTL_CDROM_MEDIA_CATALOG
:
2491 transferByteCount
= sizeof(SUB_Q_MEDIA_CATALOG_NUMBER
);
2494 case IOCTL_CDROM_TRACK_ISRC
:
2495 transferByteCount
= sizeof(SUB_Q_TRACK_ISRC
);
2499 cdb
->SUBCHANNEL
.AllocationLength
[0] = (UCHAR
) (transferByteCount
>> 8);
2500 cdb
->SUBCHANNEL
.AllocationLength
[1] = (UCHAR
) (transferByteCount
& 0xFF);
2501 cdb
->SUBCHANNEL
.OperationCode
= SCSIOP_READ_SUB_CHANNEL
;
2502 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2503 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
2504 srb
->DataTransferLength
= transferByteCount
;
2505 srb
->CdbLength
= 10;
2506 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2508 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2513 case IOCTL_CDROM_PAUSE_AUDIO
: {
2515 cdb
->PAUSE_RESUME
.OperationCode
= SCSIOP_PAUSE_RESUME
;
2516 cdb
->PAUSE_RESUME
.Action
= CDB_AUDIO_PAUSE
;
2518 srb
->CdbLength
= 10;
2519 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2520 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2521 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_NO_DATA_TRANSFER
);
2523 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2527 case IOCTL_CDROM_RESUME_AUDIO
: {
2529 cdb
->PAUSE_RESUME
.OperationCode
= SCSIOP_PAUSE_RESUME
;
2530 cdb
->PAUSE_RESUME
.Action
= CDB_AUDIO_RESUME
;
2532 srb
->CdbLength
= 10;
2533 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2534 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2535 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_NO_DATA_TRANSFER
);
2537 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2541 case IOCTL_CDROM_SEEK_AUDIO_MSF
: {
2543 PCDROM_SEEK_AUDIO_MSF inputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
2544 ULONG logicalBlockAddress
;
2546 logicalBlockAddress
= MSF_TO_LBA(inputBuffer
->M
, inputBuffer
->S
, inputBuffer
->F
);
2548 cdb
->SEEK
.OperationCode
= SCSIOP_SEEK
;
2549 cdb
->SEEK
.LogicalBlockAddress
[0] = ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte3
;
2550 cdb
->SEEK
.LogicalBlockAddress
[1] = ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte2
;
2551 cdb
->SEEK
.LogicalBlockAddress
[2] = ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte1
;
2552 cdb
->SEEK
.LogicalBlockAddress
[3] = ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte0
;
2554 srb
->CdbLength
= 10;
2555 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2556 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2557 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_NO_DATA_TRANSFER
);
2559 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2564 case IOCTL_CDROM_STOP_AUDIO
: {
2566 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
2567 cdb
->START_STOP
.Immediate
= 1;
2568 cdb
->START_STOP
.Start
= 0;
2569 cdb
->START_STOP
.LoadEject
= 0;
2572 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2574 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2575 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_NO_DATA_TRANSFER
);
2577 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2581 case IOCTL_CDROM_GET_CONTROL
: {
2583 // Allocate buffer for volume control information.
2586 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
2590 Irp
->IoStatus
.Information
= 0;
2591 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2592 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2593 ExFreePool(senseBuffer
);
2596 IoStartNextPacket(DeviceObject
, FALSE
);
2601 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2607 if (!irp2
->MdlAddress
) {
2608 Irp
->IoStatus
.Information
= 0;
2609 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2610 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2611 ExFreePool(senseBuffer
);
2613 ExFreePool(dataBuffer
);
2615 IoStartNextPacket(DeviceObject
, FALSE
);
2623 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2624 srb
->DataBuffer
= dataBuffer
;
2626 RtlZeroMemory(dataBuffer
, MODE_DATA_SIZE
);
2629 // Setup for either 6 or 10 byte CDBs.
2634 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
2635 cdb
->MODE_SENSE
.PageCode
= CDROM_AUDIO_CONTROL_PAGE
;
2636 cdb
->MODE_SENSE
.AllocationLength
= MODE_DATA_SIZE
;
2639 // Disable block descriptors.
2642 cdb
->MODE_SENSE
.Dbd
= TRUE
;
2647 cdb
->MODE_SENSE10
.OperationCode
= SCSIOP_MODE_SENSE10
;
2648 cdb
->MODE_SENSE10
.PageCode
= CDROM_AUDIO_CONTROL_PAGE
;
2649 cdb
->MODE_SENSE10
.AllocationLength
[0] = (UCHAR
)(MODE_DATA_SIZE
>> 8);
2650 cdb
->MODE_SENSE10
.AllocationLength
[1] = (UCHAR
)(MODE_DATA_SIZE
& 0xFF);
2653 // Disable block descriptors.
2656 cdb
->MODE_SENSE10
.Dbd
= TRUE
;
2658 srb
->CdbLength
= 10;
2661 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2662 srb
->DataTransferLength
= MODE_DATA_SIZE
;
2663 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2664 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
2666 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2671 case IOCTL_CDROM_GET_VOLUME
:
2672 case IOCTL_CDROM_SET_VOLUME
: {
2674 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
2678 Irp
->IoStatus
.Information
= 0;
2679 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2680 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2681 ExFreePool(senseBuffer
);
2684 IoStartNextPacket(DeviceObject
, FALSE
);
2688 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2694 if (!irp2
->MdlAddress
) {
2695 Irp
->IoStatus
.Information
= 0;
2696 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2697 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2698 ExFreePool(senseBuffer
);
2700 ExFreePool(dataBuffer
);
2702 IoStartNextPacket(DeviceObject
, FALSE
);
2710 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2711 srb
->DataBuffer
= dataBuffer
;
2713 RtlZeroMemory(dataBuffer
, MODE_DATA_SIZE
);
2717 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
2718 cdb
->MODE_SENSE
.PageCode
= CDROM_AUDIO_CONTROL_PAGE
;
2719 cdb
->MODE_SENSE
.AllocationLength
= MODE_DATA_SIZE
;
2725 cdb
->MODE_SENSE10
.OperationCode
= SCSIOP_MODE_SENSE10
;
2726 cdb
->MODE_SENSE10
.PageCode
= CDROM_AUDIO_CONTROL_PAGE
;
2727 cdb
->MODE_SENSE10
.AllocationLength
[0] = (UCHAR
)(MODE_DATA_SIZE
>> 8);
2728 cdb
->MODE_SENSE10
.AllocationLength
[1] = (UCHAR
)(MODE_DATA_SIZE
& 0xFF);
2730 srb
->CdbLength
= 10;
2733 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2734 srb
->DataTransferLength
= MODE_DATA_SIZE
;
2735 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2736 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
2738 if (currentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_SET_VOLUME
) {
2741 // Setup a different completion routine as the mode sense data is needed in order
2742 // to send the mode select.
2745 IoSetCompletionRoutine(irp2
,
2746 CdRomSetVolumeIntermediateCompletion
,
2754 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2762 // Just complete the request - CdRomClassIoctlCompletion will take
2763 // care of it for us
2766 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2773 // If a read or an unhandled IRP_MJ_XX, end up here. The unhandled IRP_MJ's
2774 // are expected and composed of AutoRun Irps, at present.
2777 IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
2784 ScsiCdRomReadVerification(
2785 IN PDEVICE_OBJECT DeviceObject
,
2791 Routine Description:
2793 This is the entry called by the I/O system for read requests.
2794 It builds the SRB and sends it to the port driver.
2798 DeviceObject - the system object for the device.
2808 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2809 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
2810 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
2811 LARGE_INTEGER startingOffset
= currentIrpStack
->Parameters
.Read
.ByteOffset
;
2814 // If the cd is playing music then reject this request.
2817 if (PLAY_ACTIVE(deviceExtension
)) {
2818 Irp
->IoStatus
.Status
= STATUS_DEVICE_BUSY
;
2819 return STATUS_DEVICE_BUSY
;
2823 // Verify parameters of this request.
2824 // Check that ending sector is on disc and
2825 // that number of bytes to transfer is a multiple of
2829 startingOffset
.QuadPart
= currentIrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+
2832 if (!deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
) {
2833 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= 2048;
2836 if ((startingOffset
.QuadPart
> deviceExtension
->PartitionLength
.QuadPart
) ||
2837 (transferByteCount
& (deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
- 1))) {
2839 DebugPrint((1,"ScsiCdRomRead: Invalid I/O parameters\n"));
2840 DebugPrint((1, "\toffset %x:%x, Length %x:%x\n",
2841 startingOffset
.u
.HighPart
,
2842 startingOffset
.u
.LowPart
,
2843 deviceExtension
->PartitionLength
.u
.HighPart
,
2844 deviceExtension
->PartitionLength
.u
.LowPart
));
2845 DebugPrint((1, "\tbps %x\n", deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
));
2848 // Fail request with status of invalid parameters.
2851 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
2853 return STATUS_INVALID_PARAMETER
;
2857 return STATUS_SUCCESS
;
2859 } // end ScsiCdRomReadVerification()
2864 CdRomDeviceControlCompletion(
2865 IN PDEVICE_OBJECT DeviceObject
,
2870 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2871 PDEVICE_EXTENSION physicalExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
2872 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
2873 PCDROM_DATA cdData
= (PCDROM_DATA
)(deviceExtension
+ 1);
2874 BOOLEAN use6Byte
= cdData
->XAFlags
& XA_USE_6_BYTE
;
2875 PIO_STACK_LOCATION realIrpStack
;
2876 PIO_STACK_LOCATION realIrpNextStack
;
2877 PSCSI_REQUEST_BLOCK srb
= Context
;
2878 PIRP realIrp
= NULL
;
2883 // Extract the 'real' irp from the irpstack.
2886 realIrp
= (PIRP
) irpStack
->Parameters
.Others
.Argument2
;
2887 realIrpStack
= IoGetCurrentIrpStackLocation(realIrp
);
2888 realIrpNextStack
= IoGetNextIrpStackLocation(realIrp
);
2891 // Check SRB status for success of completing request.
2894 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
2897 "CdRomDeviceControlCompletion: Irp %lx, Srb %lx Real Irp %lx Status %lx\n",
2904 // Release the queue if it is frozen.
2907 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
2908 DebugPrint((2, "CdRomDeviceControlCompletion: Releasing Queue\n"));
2909 ScsiClassReleaseQueue(DeviceObject
);
2913 retry
= ScsiClassInterpretSenseInfo(DeviceObject
,
2915 irpStack
->MajorFunction
,
2916 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
,
2917 MAXIMUM_RETRIES
- ((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
),
2920 DebugPrint((2, "CdRomDeviceControlCompletion: IRP will %sbe retried\n",
2921 (retry
? "" : "not ")));
2924 // Some of the Device Controls need special cases on non-Success status's.
2927 if (realIrpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
) {
2928 if ((realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_GET_LAST_SESSION
) ||
2929 (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_READ_TOC
) ||
2930 (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_GET_CONTROL
) ||
2931 (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_GET_VOLUME
)) {
2933 if (status
== STATUS_DATA_OVERRUN
) {
2934 status
= STATUS_SUCCESS
;
2939 if (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_READ_Q_CHANNEL
) {
2940 PLAY_ACTIVE(deviceExtension
) = FALSE
;
2945 // If the status is verified required and the this request
2946 // should bypass verify required then retry the request.
2949 if (realIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
2950 status
== STATUS_VERIFY_REQUIRED
) {
2952 if (((realIrpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
) ||
2953 (realIrpStack
->MajorFunction
== IRP_MJ_INTERNAL_DEVICE_CONTROL
)) &&
2954 (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_CHECK_VERIFY
)) {
2957 // Update the geometry information, as the media could have changed.
2958 // The completion routine for this will complete the real irp and start
2962 status
= CdRomUpdateCapacity(deviceExtension
,realIrp
, NULL
);
2963 DebugPrint((2, "CdRomDeviceControlCompletion: [%lx] CdRomUpdateCapacity completed with status %lx\n", realIrp
, status
));
2964 ASSERT(status
== STATUS_PENDING
);
2966 return STATUS_MORE_PROCESSING_REQUIRED
;
2970 status
= STATUS_IO_DEVICE_ERROR
;
2976 if (retry
&& (realIrpNextStack
->Parameters
.Others
.Argument1
= (PVOID
)((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
-1))) {
2979 if (((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
)) {
2985 DebugPrint((1, "Retry request %lx - Calling StartIo\n", Irp
));
2988 ExFreePool(srb
->SenseInfoBuffer
);
2989 if (srb
->DataBuffer
) {
2990 ExFreePool(srb
->DataBuffer
);
2993 if (Irp
->MdlAddress
) {
2994 IoFreeMdl(Irp
->MdlAddress
);
3000 // Call StartIo directly since IoStartNextPacket hasn't been called,
3001 // the serialisation is still intact.
3004 ScsiCdRomStartIo(DeviceObject
, realIrp
);
3005 return STATUS_MORE_PROCESSING_REQUIRED
;
3010 // Exhausted retries. Fall through and complete the request with the appropriate status.
3017 // Set status for successful request.
3020 status
= STATUS_SUCCESS
;
3023 if (NT_SUCCESS(status
)) {
3025 switch (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
) {
3027 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
: {
3029 PREAD_CAPACITY_DATA readCapacityBuffer
= srb
->DataBuffer
;
3036 // Swizzle bytes from Read Capacity and translate into
3037 // the necessary geometry information in the device extension.
3040 tmp
= readCapacityBuffer
->BytesPerBlock
;
3041 ((PFOUR_BYTE
)&bps
)->Byte0
= ((PFOUR_BYTE
)&tmp
)->Byte3
;
3042 ((PFOUR_BYTE
)&bps
)->Byte1
= ((PFOUR_BYTE
)&tmp
)->Byte2
;
3043 ((PFOUR_BYTE
)&bps
)->Byte2
= ((PFOUR_BYTE
)&tmp
)->Byte1
;
3044 ((PFOUR_BYTE
)&bps
)->Byte3
= ((PFOUR_BYTE
)&tmp
)->Byte0
;
3047 // Insure that bps is a power of 2.
3048 // This corrects a problem with the HP 4020i CDR where it
3049 // returns an incorrect number for bytes per sector.
3055 lastBit
= (ULONG
) -1;
3063 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= bps
;
3066 "CdRomDeviceControlCompletion: Calculated bps %#x\n",
3067 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
));
3070 // Copy last sector in reverse byte order.
3073 tmp
= readCapacityBuffer
->LogicalBlockAddress
;
3074 ((PFOUR_BYTE
)&lastSector
)->Byte0
= ((PFOUR_BYTE
)&tmp
)->Byte3
;
3075 ((PFOUR_BYTE
)&lastSector
)->Byte1
= ((PFOUR_BYTE
)&tmp
)->Byte2
;
3076 ((PFOUR_BYTE
)&lastSector
)->Byte2
= ((PFOUR_BYTE
)&tmp
)->Byte1
;
3077 ((PFOUR_BYTE
)&lastSector
)->Byte3
= ((PFOUR_BYTE
)&tmp
)->Byte0
;
3080 // Calculate sector to byte shift.
3083 WHICH_BIT(bps
, deviceExtension
->SectorShift
);
3085 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Sector size is %d\n",
3086 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
));
3088 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Number of Sectors is %d\n",
3092 // Calculate media capacity in bytes.
3095 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(lastSector
+ 1);
3098 // Calculate number of cylinders.
3101 deviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
= (LONGLONG
)((lastSector
+ 1)/(32 * 64));
3103 deviceExtension
->PartitionLength
.QuadPart
=
3104 (deviceExtension
->PartitionLength
.QuadPart
<< deviceExtension
->SectorShift
);
3106 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
3109 // This device supports removable media.
3112 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= RemovableMedia
;
3117 // Assume media type is fixed disk.
3120 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= FixedMedia
;
3124 // Assume sectors per track are 32;
3127 deviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
= 32;
3130 // Assume tracks per cylinder (number of heads) is 64.
3133 deviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
= 64;
3136 // Copy the device extension's geometry info into the user buffer.
3139 RtlMoveMemory(realIrp
->AssociatedIrp
.SystemBuffer
,
3140 deviceExtension
->DiskGeometry
,
3141 sizeof(DISK_GEOMETRY
));
3144 // update information field.
3147 realIrp
->IoStatus
.Information
= sizeof(DISK_GEOMETRY
);
3151 case IOCTL_CDROM_CHECK_VERIFY
:
3153 if((realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_CHECK_VERIFY
) &&
3154 (realIrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
)) {
3156 *((PULONG
)realIrp
->AssociatedIrp
.SystemBuffer
) =
3157 physicalExtension
->MediaChangeCount
;
3158 realIrp
->IoStatus
.Information
= sizeof(ULONG
);
3160 realIrp
->IoStatus
.Information
= 0;
3163 DebugPrint((2, "CdRomDeviceControlCompletion: [%lx] completing CHECK_VERIFY buddy irp %lx\n", realIrp
, Irp
));
3166 case IOCTL_CDROM_GET_LAST_SESSION
:
3167 case IOCTL_CDROM_READ_TOC
: {
3169 PCDROM_TOC toc
= srb
->DataBuffer
;
3172 // Copy the device extension's geometry info into the user buffer.
3175 RtlMoveMemory(realIrp
->AssociatedIrp
.SystemBuffer
,
3177 srb
->DataTransferLength
);
3180 // update information field.
3183 realIrp
->IoStatus
.Information
= srb
->DataTransferLength
;
3187 case IOCTL_CDROM_PLAY_AUDIO_MSF
:
3189 PLAY_ACTIVE(deviceExtension
) = TRUE
;
3193 case IOCTL_CDROM_READ_Q_CHANNEL
: {
3195 PSUB_Q_CHANNEL_DATA userChannelData
= realIrp
->AssociatedIrp
.SystemBuffer
;
3197 PCDROM_SUB_Q_DATA_FORMAT inputBuffer
= realIrp
->AssociatedIrp
.SystemBuffer
;
3199 PSUB_Q_CHANNEL_DATA subQPtr
= srb
->DataBuffer
;
3202 switch( inputBuffer
->Format
) {
3204 case IOCTL_CDROM_CURRENT_POSITION
:
3205 DebugPrint((2,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr
->CurrentPosition
.Header
.AudioStatus
));
3206 DebugPrint((2,"CdRomDeviceControlCompletion: ADR = 0x%x\n", subQPtr
->CurrentPosition
.ADR
));
3207 DebugPrint((2,"CdRomDeviceControlCompletion: Control = 0x%x\n", subQPtr
->CurrentPosition
.Control
));
3208 DebugPrint((2,"CdRomDeviceControlCompletion: Track = %u\n", subQPtr
->CurrentPosition
.TrackNumber
));
3209 DebugPrint((2,"CdRomDeviceControlCompletion: Index = %u\n", subQPtr
->CurrentPosition
.IndexNumber
));
3210 DebugPrint((2,"CdRomDeviceControlCompletion: Absolute Address = %x\n", *((PULONG
)subQPtr
->CurrentPosition
.AbsoluteAddress
) ));
3211 DebugPrint((2,"CdRomDeviceControlCompletion: Relative Address = %x\n", *((PULONG
)subQPtr
->CurrentPosition
.TrackRelativeAddress
) ));
3214 case IOCTL_CDROM_MEDIA_CATALOG
:
3215 DebugPrint((2,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr
->MediaCatalog
.Header
.AudioStatus
));
3216 DebugPrint((2,"CdRomDeviceControlCompletion: Mcval is %u\n", subQPtr
->MediaCatalog
.Mcval
));
3219 case IOCTL_CDROM_TRACK_ISRC
:
3220 DebugPrint((2,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr
->TrackIsrc
.Header
.AudioStatus
));
3221 DebugPrint((2,"CdRomDeviceControlCompletion: Tcval is %u\n", subQPtr
->TrackIsrc
.Tcval
));
3228 // Update the play active status.
3231 if (subQPtr
->CurrentPosition
.Header
.AudioStatus
== AUDIO_STATUS_IN_PROGRESS
) {
3233 PLAY_ACTIVE(deviceExtension
) = TRUE
;
3237 PLAY_ACTIVE(deviceExtension
) = FALSE
;
3242 // Check if output buffer is large enough to contain
3246 if (realIrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
3247 srb
->DataTransferLength
) {
3249 srb
->DataTransferLength
=
3250 realIrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
3254 // Copy our buffer into users.
3257 RtlMoveMemory(userChannelData
,
3259 srb
->DataTransferLength
);
3261 realIrp
->IoStatus
.Information
= srb
->DataTransferLength
;
3265 case IOCTL_CDROM_PAUSE_AUDIO
:
3267 PLAY_ACTIVE(deviceExtension
) = FALSE
;
3268 realIrp
->IoStatus
.Information
= 0;
3271 case IOCTL_CDROM_RESUME_AUDIO
:
3273 realIrp
->IoStatus
.Information
= 0;
3276 case IOCTL_CDROM_SEEK_AUDIO_MSF
:
3278 realIrp
->IoStatus
.Information
= 0;
3281 case IOCTL_CDROM_STOP_AUDIO
:
3283 PLAY_ACTIVE(deviceExtension
) = FALSE
;
3285 realIrp
->IoStatus
.Information
= 0;
3288 case IOCTL_CDROM_GET_CONTROL
: {
3290 PCDROM_AUDIO_CONTROL audioControl
= srb
->DataBuffer
;
3291 PAUDIO_OUTPUT audioOutput
;
3292 ULONG bytesTransferred
;
3294 audioOutput
= ScsiClassFindModePage((PCHAR
)audioControl
,
3295 srb
->DataTransferLength
,
3296 CDROM_AUDIO_CONTROL_PAGE
,
3299 // Verify the page is as big as expected.
3302 bytesTransferred
= (PCHAR
) audioOutput
- (PCHAR
) audioControl
+
3303 sizeof(AUDIO_OUTPUT
);
3305 if (audioOutput
!= NULL
&&
3306 srb
->DataTransferLength
>= bytesTransferred
) {
3308 audioControl
->LbaFormat
= audioOutput
->LbaFormat
;
3310 audioControl
->LogicalBlocksPerSecond
=
3311 (audioOutput
->LogicalBlocksPerSecond
[0] << (UCHAR
)8) |
3312 audioOutput
->LogicalBlocksPerSecond
[1];
3314 realIrp
->IoStatus
.Information
= sizeof(CDROM_AUDIO_CONTROL
);
3317 realIrp
->IoStatus
.Information
= 0;
3318 status
= STATUS_INVALID_DEVICE_REQUEST
;
3323 case IOCTL_CDROM_GET_VOLUME
: {
3325 PAUDIO_OUTPUT audioOutput
;
3326 PVOLUME_CONTROL volumeControl
= srb
->DataBuffer
;
3327 ULONG i
,bytesTransferred
;
3329 audioOutput
= ScsiClassFindModePage((PCHAR
)volumeControl
,
3330 srb
->DataTransferLength
,
3331 CDROM_AUDIO_CONTROL_PAGE
,
3335 // Verify the page is as big as expected.
3338 bytesTransferred
= (PCHAR
) audioOutput
- (PCHAR
) volumeControl
+
3339 sizeof(AUDIO_OUTPUT
);
3341 if (audioOutput
!= NULL
&&
3342 srb
->DataTransferLength
>= bytesTransferred
) {
3344 for (i
=0; i
<4; i
++) {
3345 volumeControl
->PortVolume
[i
] =
3346 audioOutput
->PortOutput
[i
].Volume
;
3350 // Set bytes transferred in IRP.
3353 realIrp
->IoStatus
.Information
= sizeof(VOLUME_CONTROL
);
3356 realIrp
->IoStatus
.Information
= 0;
3357 status
= STATUS_INVALID_DEVICE_REQUEST
;
3363 case IOCTL_CDROM_SET_VOLUME
:
3365 realIrp
->IoStatus
.Information
= sizeof(VOLUME_CONTROL
);
3371 realIrp
->IoStatus
.Information
= 0;
3372 status
= STATUS_INVALID_DEVICE_REQUEST
;
3378 // Deallocate srb and sense buffer.
3382 if (srb
->DataBuffer
) {
3383 ExFreePool(srb
->DataBuffer
);
3385 if (srb
->SenseInfoBuffer
) {
3386 ExFreePool(srb
->SenseInfoBuffer
);
3391 if (realIrp
->PendingReturned
) {
3392 IoMarkIrpPending(realIrp
);
3395 if (Irp
->MdlAddress
) {
3396 IoFreeMdl(Irp
->MdlAddress
);
3402 // Set status in completing IRP.
3405 realIrp
->IoStatus
.Status
= status
;
3408 // Set the hard error if necessary.
3411 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
3414 // Store DeviceObject for filesystem, and clear
3415 // in IoStatus.Information field.
3418 DebugPrint((1, "CdRomDeviceCompletion - Setting Hard Error on realIrp %lx\n",
3420 IoSetHardErrorOrVerifyDevice(realIrp
, DeviceObject
);
3421 realIrp
->IoStatus
.Information
= 0;
3424 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
3426 IoStartNextPacket(DeviceObject
, FALSE
);
3428 return STATUS_MORE_PROCESSING_REQUIRED
;
3433 CdRomSetVolumeIntermediateCompletion(
3434 IN PDEVICE_OBJECT DeviceObject
,
3439 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3440 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3441 PCDROM_DATA cdData
= (PCDROM_DATA
)(deviceExtension
+ 1);
3442 BOOLEAN use6Byte
= cdData
->XAFlags
& XA_USE_6_BYTE
;
3443 PIO_STACK_LOCATION realIrpStack
;
3444 PIO_STACK_LOCATION realIrpNextStack
;
3445 PSCSI_REQUEST_BLOCK srb
= Context
;
3446 PIRP realIrp
= NULL
;
3451 // Extract the 'real' irp from the irpstack.
3454 realIrp
= (PIRP
) irpStack
->Parameters
.Others
.Argument2
;
3455 realIrpStack
= IoGetCurrentIrpStackLocation(realIrp
);
3456 realIrpNextStack
= IoGetNextIrpStackLocation(realIrp
);
3459 // Check SRB status for success of completing request.
3462 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
3465 "CdRomSetVolumeIntermediateCompletion: Irp %lx, Srb %lx Real Irp\n",
3471 // Release the queue if it is frozen.
3474 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
3475 ScsiClassReleaseQueue(DeviceObject
);
3479 retry
= ScsiClassInterpretSenseInfo(DeviceObject
,
3481 irpStack
->MajorFunction
,
3482 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
,
3483 MAXIMUM_RETRIES
- ((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
),
3486 if (status
== STATUS_DATA_OVERRUN
) {
3487 status
= STATUS_SUCCESS
;
3492 // If the status is verified required and the this request
3493 // should bypass verify required then retry the request.
3496 if (realIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
3497 status
== STATUS_VERIFY_REQUIRED
) {
3499 status
= STATUS_IO_DEVICE_ERROR
;
3503 if (retry
&& (realIrpNextStack
->Parameters
.Others
.Argument1
= (PVOID
)((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
-1))) {
3505 if (((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
)) {
3511 DebugPrint((1, "Retry request %lx - Calling StartIo\n", Irp
));
3514 ExFreePool(srb
->SenseInfoBuffer
);
3515 ExFreePool(srb
->DataBuffer
);
3517 if (Irp
->MdlAddress
) {
3518 IoFreeMdl(Irp
->MdlAddress
);
3524 // Call StartIo directly since IoStartNextPacket hasn't been called,
3525 // the serialisation is still intact.
3527 ScsiCdRomStartIo(DeviceObject
, realIrp
);
3528 return STATUS_MORE_PROCESSING_REQUIRED
;
3533 // Exhausted retries. Fall through and complete the request with the appropriate status.
3540 // Set status for successful request.
3543 status
= STATUS_SUCCESS
;
3546 if (NT_SUCCESS(status
)) {
3548 PAUDIO_OUTPUT audioInput
= NULL
;
3549 PAUDIO_OUTPUT audioOutput
;
3550 PVOLUME_CONTROL volumeControl
= realIrp
->AssociatedIrp
.SystemBuffer
;
3551 ULONG i
,bytesTransferred
,headerLength
;
3555 audioInput
= ScsiClassFindModePage((PCHAR
)srb
->DataBuffer
,
3556 srb
->DataTransferLength
,
3557 CDROM_AUDIO_CONTROL_PAGE
,
3561 // Check to make sure the mode sense data is valid before we go on
3564 if(audioInput
== NULL
) {
3566 DebugPrint((1, "Mode Sense Page %d not found\n",
3567 CDROM_AUDIO_CONTROL_PAGE
));
3569 realIrp
->IoStatus
.Information
= 0;
3570 realIrp
->IoStatus
.Status
= STATUS_IO_DEVICE_ERROR
;
3571 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
3572 ExFreePool(srb
->SenseInfoBuffer
);
3574 IoFreeMdl(Irp
->MdlAddress
);
3576 return STATUS_MORE_PROCESSING_REQUIRED
;
3580 headerLength
= sizeof(MODE_PARAMETER_HEADER
);
3582 headerLength
= sizeof(MODE_PARAMETER_HEADER10
);
3585 bytesTransferred
= sizeof(AUDIO_OUTPUT
) + headerLength
;
3588 // Allocate a new buffer for the mode select.
3591 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, bytesTransferred
);
3594 realIrp
->IoStatus
.Information
= 0;
3595 realIrp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3596 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
3597 ExFreePool(srb
->SenseInfoBuffer
);
3599 IoFreeMdl(Irp
->MdlAddress
);
3601 return STATUS_MORE_PROCESSING_REQUIRED
;
3604 RtlZeroMemory(dataBuffer
, bytesTransferred
);
3607 // Rebuild the data buffer to include the user requested values.
3610 audioOutput
= (PAUDIO_OUTPUT
) ((PCHAR
) dataBuffer
+ headerLength
);
3612 for (i
=0; i
<4; i
++) {
3613 audioOutput
->PortOutput
[i
].Volume
=
3614 volumeControl
->PortVolume
[i
];
3615 audioOutput
->PortOutput
[i
].ChannelSelection
=
3616 audioInput
->PortOutput
[i
].ChannelSelection
;
3619 audioOutput
->CodePage
= CDROM_AUDIO_CONTROL_PAGE
;
3620 audioOutput
->ParameterLength
= sizeof(AUDIO_OUTPUT
) - 2;
3621 audioOutput
->Immediate
= MODE_SELECT_IMMEDIATE
;
3624 // Free the old data buffer, mdl.
3627 ExFreePool(srb
->DataBuffer
);
3628 IoFreeMdl(Irp
->MdlAddress
);
3634 cdb
= (PCDB
)srb
->Cdb
;
3635 RtlZeroMemory(cdb
, CDB12GENERIC_LENGTH
);
3637 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
3638 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
3639 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_OUT
);
3640 srb
->DataTransferLength
= bytesTransferred
;
3644 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
3645 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
) bytesTransferred
;
3646 cdb
->MODE_SELECT
.PFBit
= 1;
3650 cdb
->MODE_SELECT10
.OperationCode
= SCSIOP_MODE_SELECT10
;
3651 cdb
->MODE_SELECT10
.ParameterListLength
[0] = (UCHAR
) (bytesTransferred
>> 8);
3652 cdb
->MODE_SELECT10
.ParameterListLength
[1] = (UCHAR
) (bytesTransferred
& 0xFF);
3653 cdb
->MODE_SELECT10
.PFBit
= 1;
3654 srb
->CdbLength
= 10;
3661 Irp
->MdlAddress
= IoAllocateMdl(dataBuffer
,
3667 if (!Irp
->MdlAddress
) {
3668 realIrp
->IoStatus
.Information
= 0;
3669 realIrp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3670 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
3671 ExFreePool(srb
->SenseInfoBuffer
);
3673 ExFreePool(dataBuffer
);
3675 return STATUS_MORE_PROCESSING_REQUIRED
;
3679 MmBuildMdlForNonPagedPool(Irp
->MdlAddress
);
3680 srb
->DataBuffer
= dataBuffer
;
3682 irpStack
= IoGetNextIrpStackLocation(Irp
);
3683 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
3684 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
3685 irpStack
->Parameters
.Scsi
.Srb
= srb
;
3688 // reset the irp completion.
3691 IoSetCompletionRoutine(Irp
,
3692 CdRomDeviceControlCompletion
,
3698 // Call the port driver.
3701 IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
3703 return STATUS_MORE_PROCESSING_REQUIRED
;
3707 // Deallocate srb and sense buffer.
3711 if (srb
->DataBuffer
) {
3712 ExFreePool(srb
->DataBuffer
);
3714 if (srb
->SenseInfoBuffer
) {
3715 ExFreePool(srb
->SenseInfoBuffer
);
3720 if (Irp
->PendingReturned
) {
3721 IoMarkIrpPending(Irp
);
3724 if (realIrp
->PendingReturned
) {
3725 IoMarkIrpPending(realIrp
);
3728 if (Irp
->MdlAddress
) {
3729 IoFreeMdl(Irp
->MdlAddress
);
3735 // Set status in completing IRP.
3738 realIrp
->IoStatus
.Status
= status
;
3741 // Set the hard error if necessary.
3744 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
3747 // Store DeviceObject for filesystem, and clear
3748 // in IoStatus.Information field.
3751 IoSetHardErrorOrVerifyDevice(realIrp
, DeviceObject
);
3752 realIrp
->IoStatus
.Information
= 0;
3755 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
3757 IoStartNextPacket(DeviceObject
, FALSE
);
3759 return STATUS_MORE_PROCESSING_REQUIRED
;
3765 CdRomSwitchModeCompletion(
3766 IN PDEVICE_OBJECT DeviceObject
,
3771 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3772 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3773 PCDROM_DATA cdData
= (PCDROM_DATA
)(deviceExtension
+ 1);
3774 PIO_STACK_LOCATION realIrpStack
;
3775 PIO_STACK_LOCATION realIrpNextStack
;
3776 PSCSI_REQUEST_BLOCK srb
= Context
;
3777 PIRP realIrp
= NULL
;
3782 // Extract the 'real' irp from the irpstack.
3785 realIrp
= (PIRP
) irpStack
->Parameters
.Others
.Argument2
;
3786 realIrpStack
= IoGetCurrentIrpStackLocation(realIrp
);
3787 realIrpNextStack
= IoGetNextIrpStackLocation(realIrp
);
3790 // Check SRB status for success of completing request.
3793 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
3796 "CdRomSetVolumeIntermediateCompletion: Irp %lx, Srb %lx Real Irp\n",
3802 // Release the queue if it is frozen.
3805 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
3806 ScsiClassReleaseQueue(DeviceObject
);
3810 retry
= ScsiClassInterpretSenseInfo(DeviceObject
,
3812 irpStack
->MajorFunction
,
3813 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
,
3814 MAXIMUM_RETRIES
- ((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
),
3818 // If the status is verified required and the this request
3819 // should bypass verify required then retry the request.
3822 if (realIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
3823 status
== STATUS_VERIFY_REQUIRED
) {
3825 status
= STATUS_IO_DEVICE_ERROR
;
3829 if (retry
&& (realIrpNextStack
->Parameters
.Others
.Argument1
= (PVOID
)((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
-1))) {
3831 if (((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
)) {
3837 DebugPrint((1, "Retry request %lx - Calling StartIo\n", Irp
));
3840 ExFreePool(srb
->SenseInfoBuffer
);
3841 ExFreePool(srb
->DataBuffer
);
3843 if (Irp
->MdlAddress
) {
3844 IoFreeMdl(Irp
->MdlAddress
);
3850 // Call StartIo directly since IoStartNextPacket hasn't been called,
3851 // the serialisation is still intact.
3854 ScsiCdRomStartIo(DeviceObject
, realIrp
);
3855 return STATUS_MORE_PROCESSING_REQUIRED
;
3860 // Exhausted retries. Fall through and complete the request with the appropriate status.
3866 // Set status for successful request.
3869 status
= STATUS_SUCCESS
;
3872 if (NT_SUCCESS(status
)) {
3874 ULONG sectorSize
, startingSector
, transferByteCount
;
3878 // Update device ext. to show which mode we are currently using.
3881 sectorSize
= cdData
->u1
.BlockDescriptor
.BlockLength
[0] << 16;
3882 sectorSize
|= (cdData
->u1
.BlockDescriptor
.BlockLength
[1] << 8);
3883 sectorSize
|= (cdData
->u1
.BlockDescriptor
.BlockLength
[2]);
3885 cdData
->RawAccess
= (sectorSize
== RAW_SECTOR_SIZE
) ? TRUE
: FALSE
;
3888 // Free the old data buffer, mdl.
3891 ExFreePool(srb
->DataBuffer
);
3892 IoFreeMdl(Irp
->MdlAddress
);
3899 cdb
= (PCDB
)srb
->Cdb
;
3900 RtlZeroMemory(cdb
, CDB12GENERIC_LENGTH
);
3903 if (cdData
->RawAccess
) {
3905 PRAW_READ_INFO rawReadInfo
=
3906 (PRAW_READ_INFO
)realIrpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
3908 ULONG maximumTransferLength
;
3909 ULONG transferPages
;
3912 // Calculate starting offset.
3915 startingSector
= (ULONG
)(rawReadInfo
->DiskOffset
.QuadPart
>> deviceExtension
->SectorShift
);
3916 transferByteCount
= rawReadInfo
->SectorCount
* RAW_SECTOR_SIZE
;
3917 maximumTransferLength
= deviceExtension
->PortCapabilities
->MaximumTransferLength
;
3918 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(realIrp
->MdlAddress
),
3922 // Determine if request is within limits imposed by miniport.
3923 // If the request is larger than the miniport's capabilities, split it.
3926 if (transferByteCount
> maximumTransferLength
||
3927 transferPages
> deviceExtension
->PortCapabilities
->MaximumPhysicalPages
) {
3929 realIrp
->IoStatus
.Information
= 0;
3930 realIrp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
3931 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
3933 ExFreePool(srb
->SenseInfoBuffer
);
3936 IoStartNextPacket(DeviceObject
, FALSE
);
3938 return STATUS_MORE_PROCESSING_REQUIRED
;
3941 srb
->OriginalRequest
= realIrp
;
3942 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
3943 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
3944 srb
->DataTransferLength
= transferByteCount
;
3945 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
3946 srb
->CdbLength
= 10;
3947 srb
->DataBuffer
= MmGetMdlVirtualAddress(realIrp
->MdlAddress
);
3949 if (rawReadInfo
->TrackMode
== CDDA
) {
3950 if (cdData
->XAFlags
& PLEXTOR_CDDA
) {
3952 srb
->CdbLength
= 12;
3954 cdb
->PLXTR_READ_CDDA
.LogicalUnitNumber
= deviceExtension
->Lun
;
3955 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
3956 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
3957 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
3958 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
3960 cdb
->PLXTR_READ_CDDA
.TransferBlockByte3
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
3961 cdb
->PLXTR_READ_CDDA
.TransferBlockByte2
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
3962 cdb
->PLXTR_READ_CDDA
.TransferBlockByte1
= 0;
3963 cdb
->PLXTR_READ_CDDA
.TransferBlockByte0
= 0;
3965 cdb
->PLXTR_READ_CDDA
.SubCode
= 0;
3966 cdb
->PLXTR_READ_CDDA
.OperationCode
= 0xD8;
3968 } else if (cdData
->XAFlags
& NEC_CDDA
) {
3970 cdb
->NEC_READ_CDDA
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
3971 cdb
->NEC_READ_CDDA
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
3972 cdb
->NEC_READ_CDDA
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
3973 cdb
->NEC_READ_CDDA
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
3975 cdb
->NEC_READ_CDDA
.TransferBlockByte1
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
3976 cdb
->NEC_READ_CDDA
.TransferBlockByte0
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
3978 cdb
->NEC_READ_CDDA
.OperationCode
= 0xD4;
3981 cdb
->CDB10
.LogicalUnitNumber
= deviceExtension
->Lun
;
3983 cdb
->CDB10
.TransferBlocksMsb
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
3984 cdb
->CDB10
.TransferBlocksLsb
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
3986 cdb
->CDB10
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
3987 cdb
->CDB10
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
3988 cdb
->CDB10
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
3989 cdb
->CDB10
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
3991 cdb
->CDB10
.OperationCode
= SCSIOP_READ
;
3994 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
3997 irpStack
= IoGetNextIrpStackLocation(realIrp
);
3998 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
3999 irpStack
->Parameters
.Scsi
.Srb
= srb
;
4001 if (!(irpStack
->Parameters
.Others
.Argument1
)) {
4004 // Only jam this in if it doesn't exist. The completion routines can
4005 // call StartIo directly in the case of retries and resetting it will
4006 // cause infinite loops.
4009 irpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
4013 // Set up IoCompletion routine address.
4016 IoSetCompletionRoutine(realIrp
,
4024 ULONG maximumTransferLength
= deviceExtension
->PortCapabilities
->MaximumTransferLength
;
4025 ULONG transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(realIrp
->MdlAddress
),
4026 realIrpStack
->Parameters
.Read
.Length
);
4028 // Back to cooked sectors. Build and send a normal read.
4029 // The real work for setting offsets and checking for splitrequests was
4033 if ((realIrpStack
->Parameters
.Read
.Length
> maximumTransferLength
) ||
4034 (transferPages
> deviceExtension
->PortCapabilities
->MaximumPhysicalPages
)) {
4037 // Request needs to be split. Completion of each portion of the request will
4038 // fire off the next portion. The final request will signal Io to send a new request.
4041 ScsiClassSplitRequest(DeviceObject
, realIrp
, maximumTransferLength
);
4042 return STATUS_MORE_PROCESSING_REQUIRED
;
4047 // Build SRB and CDB for this IRP.
4050 ScsiClassBuildRequest(DeviceObject
, realIrp
);
4056 // Call the port driver.
4059 IoCallDriver(deviceExtension
->PortDeviceObject
, realIrp
);
4061 return STATUS_MORE_PROCESSING_REQUIRED
;
4065 // Update device Extension flags to indicate that XA isn't supported.
4068 cdData
->XAFlags
|= XA_NOT_SUPPORTED
;
4071 // Deallocate srb and sense buffer.
4075 if (srb
->DataBuffer
) {
4076 ExFreePool(srb
->DataBuffer
);
4078 if (srb
->SenseInfoBuffer
) {
4079 ExFreePool(srb
->SenseInfoBuffer
);
4084 if (Irp
->PendingReturned
) {
4085 IoMarkIrpPending(Irp
);
4088 if (realIrp
->PendingReturned
) {
4089 IoMarkIrpPending(realIrp
);
4092 if (Irp
->MdlAddress
) {
4093 IoFreeMdl(Irp
->MdlAddress
);
4099 // Set status in completing IRP.
4102 realIrp
->IoStatus
.Status
= status
;
4105 // Set the hard error if necessary.
4108 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
4111 // Store DeviceObject for filesystem, and clear
4112 // in IoStatus.Information field.
4115 IoSetHardErrorOrVerifyDevice(realIrp
, DeviceObject
);
4116 realIrp
->IoStatus
.Information
= 0;
4119 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
4121 IoStartNextPacket(DeviceObject
, FALSE
);
4123 return STATUS_MORE_PROCESSING_REQUIRED
;
4129 IN PDEVICE_OBJECT DeviceObject
,
4136 Routine Description:
4138 This routine executes when the port driver has completed a request.
4139 It looks at the SRB status in the completing SRB and if not success
4140 it checks for valid request sense buffer information. If valid, the
4141 info is used to update status with more precise message of type of
4142 error. This routine deallocates the SRB.
4146 DeviceObject - Supplies the device object which represents the logical
4149 Irp - Supplies the Irp which has completed.
4151 Context - Supplies a pointer to the SRB.
4160 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
4161 PIO_STACK_LOCATION irpNextStack
= IoGetNextIrpStackLocation(Irp
);
4162 PSCSI_REQUEST_BLOCK srb
= Context
;
4167 // Check SRB status for success of completing request.
4170 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
4172 DebugPrint((2,"ScsiClassIoComplete: IRP %lx, SRB %lx\n", Irp
, srb
));
4175 // Release the queue if it is frozen.
4178 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
4179 ScsiClassReleaseQueue(DeviceObject
);
4182 retry
= ScsiClassInterpretSenseInfo(
4185 irpStack
->MajorFunction
,
4186 irpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
? irpStack
->Parameters
.DeviceIoControl
.IoControlCode
: 0,
4187 MAXIMUM_RETRIES
- ((ULONG_PTR
)irpNextStack
->Parameters
.Others
.Argument1
),
4191 // If the status is verified required and the this request
4192 // should bypass verify required then retry the request.
4195 if (irpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
4196 status
== STATUS_VERIFY_REQUIRED
) {
4198 status
= STATUS_IO_DEVICE_ERROR
;
4202 if (retry
&& (irpNextStack
->Parameters
.Others
.Argument1
= (PVOID
)((ULONG_PTR
)irpNextStack
->Parameters
.Others
.Argument1
-1))) {
4204 if (((ULONG_PTR
)irpNextStack
->Parameters
.Others
.Argument1
)) {
4210 DebugPrint((1, "CdRomXACompletion: Retry request %lx - Calling StartIo\n", Irp
));
4213 ExFreePool(srb
->SenseInfoBuffer
);
4214 ExFreePool(srb
->DataBuffer
);
4218 // Call StartIo directly since IoStartNextPacket hasn't been called,
4219 // the serialisation is still intact.
4222 ScsiCdRomStartIo(DeviceObject
, Irp
);
4223 return STATUS_MORE_PROCESSING_REQUIRED
;
4228 // Exhausted retries. Fall through and complete the request with the appropriate status.
4234 // Set status for successful request.
4237 status
= STATUS_SUCCESS
;
4239 } // end if (SRB_STATUS(srb->SrbStatus) ...
4242 // Return SRB to nonpaged pool.
4248 // Set status in completing IRP.
4251 Irp
->IoStatus
.Status
= status
;
4254 // Set the hard error if necessary.
4257 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
4260 // Store DeviceObject for filesystem, and clear
4261 // in IoStatus.Information field.
4264 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
4265 Irp
->IoStatus
.Information
= 0;
4269 // If pending has be returned for this irp then mark the current stack as
4273 if (Irp
->PendingReturned
) {
4274 IoMarkIrpPending(Irp
);
4277 //IoCompleteRequest(Irp, IO_DISK_INCREMENT);
4278 IoStartNextPacket(DeviceObject
, FALSE
);
4286 IN PDEVICE_OBJECT DeviceObject
,
4292 Routine Description:
4294 This is the NT device control handler for CDROMs.
4298 DeviceObject - for this CDROM
4300 Irp - IO Request packet
4309 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
4310 PIO_STACK_LOCATION nextStack
;
4311 PKEVENT deviceControlEvent
;
4312 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4313 PCDROM_DATA cdData
= (PCDROM_DATA
)(deviceExtension
+1);
4314 SCSI_REQUEST_BLOCK srb
;
4325 // Zero the SRB on stack.
4328 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
4330 Irp
->IoStatus
.Information
= 0;
4333 // if this is a class driver ioctl then we need to change the base code
4334 // to IOCTL_CDROM_BASE so that the switch statement can handle it.
4336 // WARNING - currently the scsi class ioctl function codes are between
4337 // 0x200 & 0x300. this routine depends on that fact
4340 ioctlCode
= irpStack
->Parameters
.DeviceIoControl
.IoControlCode
;
4341 baseCode
= ioctlCode
>> 16;
4342 functionCode
= (ioctlCode
& (~0xffffc003)) >> 2;
4344 DebugPrint((1, "CdRomDeviceControl: Ioctl Code = %#08lx, Base Code = %#lx,"
4345 " Function Code = %#lx\n",
4351 if((functionCode
>= 0x200) && (functionCode
<= 0x300)) {
4353 ioctlCode
= (ioctlCode
& 0x0000ffff) | CTL_CODE(IOCTL_CDROM_BASE
, 0, 0, 0);
4355 DebugPrint((1, "CdRomDeviceControl: Class Code - new ioctl code is %#08lx\n",
4358 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= ioctlCode
;
4362 switch (ioctlCode
) {
4364 case IOCTL_CDROM_RAW_READ
: {
4366 LARGE_INTEGER startingOffset
;
4367 ULONG transferBytes
;
4368 PRAW_READ_INFO rawReadInfo
= (PRAW_READ_INFO
)irpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
4369 PUCHAR userData
= (PUCHAR
)Irp
->AssociatedIrp
.SystemBuffer
;
4372 // Ensure that XA reads are supported.
4375 if (cdData
->XAFlags
& XA_NOT_SUPPORTED
) {
4378 "CdRomDeviceControl: XA Reads not supported. Flags (%x)\n",
4381 status
= STATUS_INVALID_DEVICE_REQUEST
;
4386 // Check that ending sector is on disc and buffers are there and of
4390 if (rawReadInfo
== NULL
) {
4393 // Called from user space. Validate the buffers.
4396 rawReadInfo
= (PRAW_READ_INFO
)userData
;
4397 irpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
= (PVOID
)userData
;
4399 if (rawReadInfo
== NULL
) {
4401 DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (No extent info\n"));
4403 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
4405 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4406 return STATUS_INVALID_PARAMETER
;
4409 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
!= sizeof(RAW_READ_INFO
)) {
4411 DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (Invalid info buffer\n"));
4413 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
4415 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4416 return STATUS_INVALID_PARAMETER
;
4420 startingOffset
.QuadPart
= rawReadInfo
->DiskOffset
.QuadPart
;
4421 transferBytes
= rawReadInfo
->SectorCount
* RAW_SECTOR_SIZE
;
4423 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< transferBytes
) {
4425 DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (Bad buffer size)\n"));
4428 // Fail request with status of invalid parameters.
4431 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
4433 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4434 return STATUS_INVALID_PARAMETER
;
4437 if ((startingOffset
.QuadPart
+ transferBytes
) > deviceExtension
->PartitionLength
.QuadPart
) {
4439 DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (Request Out of Bounds)\n"));
4442 // Fail request with status of invalid parameters.
4445 status
= STATUS_INVALID_PARAMETER
;
4449 IoMarkIrpPending(Irp
);
4450 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4452 return STATUS_PENDING
;
4455 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
: {
4457 DebugPrint((2,"CdRomDeviceControl: Get drive geometry\n"));
4459 if ( irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
4460 sizeof( DISK_GEOMETRY
) ) {
4462 status
= STATUS_INFO_LENGTH_MISMATCH
;
4466 IoMarkIrpPending(Irp
);
4467 IoStartPacket(DeviceObject
,Irp
, NULL
,NULL
);
4469 return STATUS_PENDING
;
4472 case IOCTL_CDROM_GET_LAST_SESSION
:
4473 case IOCTL_CDROM_READ_TOC
: {
4476 // If the cd is playing music then reject this request.
4479 if (CdRomIsPlayActive(DeviceObject
)) {
4480 Irp
->IoStatus
.Status
= STATUS_DEVICE_BUSY
;
4481 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4482 return STATUS_DEVICE_BUSY
;
4485 IoMarkIrpPending(Irp
);
4486 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4488 return STATUS_PENDING
;
4491 case IOCTL_CDROM_PLAY_AUDIO_MSF
: {
4497 DebugPrint((2,"CdRomDeviceControl: Play audio MSF\n"));
4499 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
4500 sizeof(CDROM_PLAY_AUDIO_MSF
)) {
4503 // Indicate unsuccessful status.
4506 status
= STATUS_BUFFER_TOO_SMALL
;
4510 IoMarkIrpPending(Irp
);
4511 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4513 return STATUS_PENDING
;
4516 case IOCTL_CDROM_SEEK_AUDIO_MSF
: {
4523 DebugPrint((2,"CdRomDeviceControl: Seek audio MSF\n"));
4525 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
4526 sizeof(CDROM_SEEK_AUDIO_MSF
)) {
4529 // Indicate unsuccessful status.
4532 status
= STATUS_BUFFER_TOO_SMALL
;
4535 IoMarkIrpPending(Irp
);
4536 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4538 return STATUS_PENDING
;
4543 case IOCTL_CDROM_PAUSE_AUDIO
: {
4549 DebugPrint((2, "CdRomDeviceControl: Pause audio\n"));
4551 IoMarkIrpPending(Irp
);
4552 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4554 return STATUS_PENDING
;
4559 case IOCTL_CDROM_RESUME_AUDIO
: {
4565 DebugPrint((2, "CdRomDeviceControl: Resume audio\n"));
4567 IoMarkIrpPending(Irp
);
4568 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4570 return STATUS_PENDING
;
4573 case IOCTL_CDROM_READ_Q_CHANNEL
: {
4575 if(irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
4576 sizeof(CDROM_SUB_Q_DATA_FORMAT
)) {
4578 status
= STATUS_BUFFER_TOO_SMALL
;
4579 Irp
->IoStatus
.Information
= 0;
4583 IoMarkIrpPending(Irp
);
4584 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4586 return STATUS_PENDING
;
4589 case IOCTL_CDROM_GET_CONTROL
: {
4591 DebugPrint((2, "CdRomDeviceControl: Get audio control\n"));
4594 // Verify user buffer is large enough for the data.
4597 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
4598 sizeof(CDROM_AUDIO_CONTROL
)) {
4601 // Indicate unsuccessful status and no data transferred.
4604 status
= STATUS_BUFFER_TOO_SMALL
;
4605 Irp
->IoStatus
.Information
= 0;
4610 IoMarkIrpPending(Irp
);
4611 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4613 return STATUS_PENDING
;
4617 case IOCTL_CDROM_GET_VOLUME
: {
4619 DebugPrint((2, "CdRomDeviceControl: Get volume control\n"));
4622 // Verify user buffer is large enough for data.
4625 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
4626 sizeof(VOLUME_CONTROL
)) {
4629 // Indicate unsuccessful status and no data transferred.
4632 status
= STATUS_BUFFER_TOO_SMALL
;
4633 Irp
->IoStatus
.Information
= 0;
4637 IoMarkIrpPending(Irp
);
4638 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4640 return STATUS_PENDING
;
4644 case IOCTL_CDROM_SET_VOLUME
: {
4646 DebugPrint((2, "CdRomDeviceControl: Set volume control\n"));
4648 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
4649 sizeof(VOLUME_CONTROL
)) {
4652 // Indicate unsuccessful status.
4655 status
= STATUS_BUFFER_TOO_SMALL
;
4659 IoMarkIrpPending(Irp
);
4660 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4662 return STATUS_PENDING
;
4666 case IOCTL_CDROM_STOP_AUDIO
: {
4672 DebugPrint((2, "CdRomDeviceControl: Stop audio\n"));
4674 IoMarkIrpPending(Irp
);
4675 IoStartPacket(DeviceObject
,Irp
, NULL
,NULL
);
4677 return STATUS_PENDING
;
4680 case IOCTL_CDROM_CHECK_VERIFY
: {
4681 DebugPrint((1, "CdRomDeviceControl: [%lx] Check Verify\n", Irp
));
4682 IoMarkIrpPending(Irp
);
4684 if((irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
) &&
4685 (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))) {
4687 DebugPrint((1, "CdRomDeviceControl: Check Verify: media count "
4688 "buffer too small\n"));
4690 status
= STATUS_BUFFER_TOO_SMALL
;
4694 IoStartPacket(DeviceObject
,Irp
, NULL
,NULL
);
4696 return STATUS_PENDING
;
4702 // allocate an event and stuff it into our stack location.
4705 deviceControlEvent
= ExAllocatePool(NonPagedPool
, sizeof(KEVENT
));
4707 if(!deviceControlEvent
) {
4709 status
= STATUS_INSUFFICIENT_RESOURCES
;
4713 PIO_STACK_LOCATION currentStack
;
4715 KeInitializeEvent(deviceControlEvent
, NotificationEvent
, FALSE
);
4717 currentStack
= IoGetCurrentIrpStackLocation(Irp
);
4718 nextStack
= IoGetNextIrpStackLocation(Irp
);
4721 // Copy the stack down a notch
4724 *nextStack
= *currentStack
;
4726 IoSetCompletionRoutine(
4728 CdRomClassIoctlCompletion
,
4735 IoSetNextIrpStackLocation(Irp
);
4737 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4738 Irp
->IoStatus
.Information
= 0;
4741 // Override volume verifies on this stack location so that we
4742 // will be forced through the synchronization. Once this location
4743 // goes away we get the old value back
4746 nextStack
->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
4748 IoMarkIrpPending(Irp
);
4750 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4753 // Wait for CdRomClassIoctlCompletion to set the event. This
4754 // ensures serialization remains intact for these unhandled device
4758 KeWaitForSingleObject(
4765 ExFreePool(deviceControlEvent
);
4767 DebugPrint((2, "CdRomDeviceControl: irp %#08lx synchronized\n", Irp
));
4770 // If an error occured then propagate that back up - we are no longer
4771 // guaranteed synchronization and the upper layers will have to
4774 // If no error occured, call down to the class driver directly
4775 // then start up the next request.
4778 if(Irp
->IoStatus
.Status
== STATUS_SUCCESS
) {
4780 status
= ScsiClassDeviceControl(DeviceObject
, Irp
);
4782 KeRaiseIrql(DISPATCH_LEVEL
, &irql
);
4784 IoStartNextPacket(DeviceObject
, FALSE
);
4795 if (status
== STATUS_VERIFY_REQUIRED
) {
4798 // If the status is verified required and this request
4799 // should bypass verify required then retry the request.
4802 if (irpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
) {
4804 status
= STATUS_IO_DEVICE_ERROR
;
4810 if (IoIsErrorUserInduced(status
)) {
4812 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
4817 // Update IRP with completion status.
4820 Irp
->IoStatus
.Status
= status
;
4823 // Complete the request.
4826 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
4827 DebugPrint((2, "CdRomDeviceControl: Status is %lx\n", status
));
4830 } // end ScsiCdRomDeviceControl()
4835 PDEVICE_OBJECT DeviceObject
,
4836 PINQUIRYDATA InquiryData
,
4837 PIO_SCSI_CAPABILITIES PortCapabilities
4842 Routine Description:
4844 This function checks to see if an SCSI logical unit requires an special
4845 initialization or error processing.
4849 DeviceObject - Supplies the device object to be tested.
4851 InquiryData - Supplies the inquiry data returned by the device of interest.
4853 PortCapabilities - Supplies the capabilities of the device object.
4862 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4863 PCDROM_DATA cdData
= (PCDROM_DATA
)(deviceExtension
+1);
4866 // Look for a Hitachi CDR-1750. Read-ahead must be disabled in order
4867 // to get this cdrom drive to work on scsi adapters that use PIO.
4870 if ((strncmp((PCHAR
)InquiryData
->VendorId
, "HITACHI CDR-1750S", strlen("HITACHI CDR-1750S")) == 0 ||
4871 strncmp((PCHAR
)InquiryData
->VendorId
, "HITACHI CDR-3650/1650S", strlen("HITACHI CDR-3650/1650S")) == 0)
4872 && PortCapabilities
->AdapterUsesPio
) {
4874 DebugPrint((1, "CdRom ScanForSpecial: Found Hitachi CDR-1750S.\n"));
4877 // Setup an error handler to reinitialize the cd rom after it is reset.
4880 deviceExtension
->ClassError
= HitachProcessError
;
4882 } else if (( RtlCompareMemory( InquiryData
->VendorId
,"FUJITSU", 7 ) == 7 ) &&
4883 (( RtlCompareMemory( InquiryData
->ProductId
,"FMCD-101", 8 ) == 8 ) ||
4884 ( RtlCompareMemory( InquiryData
->ProductId
,"FMCD-102", 8 ) == 8 ))) {
4887 // When Read command is issued to FMCD-101 or FMCD-102 and there is a music
4888 // cd in it. It takes longer time than SCSI_CDROM_TIMEOUT before returning
4892 deviceExtension
->TimeOutValue
= 20;
4894 } else if (( RtlCompareMemory( InquiryData
->VendorId
,"TOSHIBA", 7) == 7) &&
4895 (( RtlCompareMemory( InquiryData
->ProductId
,"CD-ROM XM-34", 12) == 12))) {
4897 SCSI_REQUEST_BLOCK srb
;
4904 // Set the density code and the error handler.
4907 length
= (sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH
);
4909 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
4912 // Build the MODE SENSE CDB.
4916 cdb
= (PCDB
)srb
.Cdb
;
4919 // Set timeout value from device extension.
4922 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
4924 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
4925 cdb
->MODE_SENSE
.PageCode
= 0x1;
4926 cdb
->MODE_SENSE
.AllocationLength
= (UCHAR
)length
;
4928 buffer
= ExAllocatePool(NonPagedPoolCacheAligned
, (sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH
));
4933 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
4939 ((PERROR_RECOVERY_DATA
)buffer
)->BlockDescriptor
.DensityCode
= 0x83;
4940 ((PERROR_RECOVERY_DATA
)buffer
)->Header
.ModeDataLength
= 0x0;
4942 RtlCopyMemory(&cdData
->u1
.Header
, buffer
, sizeof(ERROR_RECOVERY_DATA
));
4944 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
4947 // Build the MODE SENSE CDB.
4951 cdb
= (PCDB
)srb
.Cdb
;
4954 // Set timeout value from device extension.
4957 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
4959 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
4960 cdb
->MODE_SELECT
.PFBit
= 1;
4961 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)length
;
4963 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
4969 if (!NT_SUCCESS(status
)) {
4971 "Cdrom.ScanForSpecial: Setting density code on Toshiba failed [%x]\n",
4975 deviceExtension
->ClassError
= ToshibaProcessError
;
4982 // Determine special CD-DA requirements.
4985 if (RtlCompareMemory( InquiryData
->VendorId
,"PLEXTOR",7) == 7) {
4986 cdData
->XAFlags
|= PLEXTOR_CDDA
;
4987 } else if (RtlCompareMemory ( InquiryData
->VendorId
,"NEC",3) == 3) {
4988 cdData
->XAFlags
|= NEC_CDDA
;
4997 PDEVICE_OBJECT DeviceObject
,
4998 PSCSI_REQUEST_BLOCK Srb
,
5004 Routine Description:
5006 This routine checks the type of error. If the error indicates CD-ROM the
5007 CD-ROM needs to be reinitialized then a Mode sense command is sent to the
5008 device. This command disables read-ahead for the device.
5012 DeviceObject - Supplies a pointer to the device object.
5014 Srb - Supplies a pointer to the failing Srb.
5027 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
5028 PSENSE_DATA senseBuffer
= Srb
->SenseInfoBuffer
;
5029 LARGE_INTEGER largeInt
;
5031 PIO_STACK_LOCATION irpStack
;
5033 PSCSI_REQUEST_BLOCK srb
;
5034 PCOMPLETION_CONTEXT context
;
5038 UNREFERENCED_PARAMETER(Status
);
5039 UNREFERENCED_PARAMETER(Retry
);
5041 largeInt
.QuadPart
= (LONGLONG
) 1;
5044 // Check the status. The initialization command only needs to be sent
5045 // if UNIT ATTENTION is returned.
5048 if (!(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
)) {
5051 // The drive does not require reinitialization.
5058 // Found a bad HITACHI cd-rom. These devices do not work with PIO
5059 // adapters when read-ahead is enabled. Read-ahead is disabled by
5060 // a mode select command. The mode select page code is zero and the
5061 // length is 6 bytes. All of the other bytes should be zero.
5065 if ((senseBuffer
->SenseKey
& 0xf) == SCSI_SENSE_UNIT_ATTENTION
) {
5067 DebugPrint((1, "HitachiProcessError: Reinitializing the CD-ROM.\n"));
5070 // Send the special mode select command to disable read-ahead
5071 // on the CD-ROM reader.
5074 alignment
= DeviceObject
->AlignmentRequirement
?
5075 DeviceObject
->AlignmentRequirement
: 1;
5077 context
= ExAllocatePool(
5079 sizeof(COMPLETION_CONTEXT
) + HITACHI_MODE_DATA_SIZE
+ alignment
5082 if (context
== NULL
) {
5085 // If there is not enough memory to fulfill this request,
5086 // simply return. A subsequent retry will fail and another
5087 // chance to start the unit.
5093 context
->DeviceObject
= DeviceObject
;
5094 srb
= &context
->Srb
;
5096 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
5099 // Write length to SRB.
5102 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
5105 // Set up SCSI bus address.
5108 srb
->PathId
= deviceExtension
->PathId
;
5109 srb
->TargetId
= deviceExtension
->TargetId
;
5110 srb
->Lun
= deviceExtension
->Lun
;
5112 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
5113 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
5116 // Set the transfer length.
5119 srb
->DataTransferLength
= HITACHI_MODE_DATA_SIZE
;
5120 srb
->SrbFlags
= SRB_FLAGS_DATA_OUT
| SRB_FLAGS_DISABLE_AUTOSENSE
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
5123 // The data buffer must be aligned.
5126 srb
->DataBuffer
= (PVOID
) (((ULONG_PTR
) (context
+ 1) + (alignment
- 1)) &
5131 // Build the HITACHI read-ahead mode select CDB.
5135 cdb
= (PCDB
)srb
->Cdb
;
5136 cdb
->MODE_SENSE
.LogicalUnitNumber
= srb
->Lun
;
5137 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SELECT
;
5138 cdb
->MODE_SENSE
.AllocationLength
= HITACHI_MODE_DATA_SIZE
;
5141 // Initialize the mode sense data.
5144 modePage
= srb
->DataBuffer
;
5146 RtlZeroMemory(modePage
, HITACHI_MODE_DATA_SIZE
);
5149 // Set the page length field to 6.
5155 // Build the asynchronous request to be sent to the port driver.
5158 irp
= IoBuildAsynchronousFsdRequest(IRP_MJ_WRITE
,
5161 srb
->DataTransferLength
,
5165 IoSetCompletionRoutine(irp
,
5166 (PIO_COMPLETION_ROUTINE
)ScsiClassAsynchronousCompletion
,
5172 irpStack
= IoGetNextIrpStackLocation(irp
);
5174 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
5176 srb
->OriginalRequest
= irp
;
5179 // Save SRB address in next stack for port driver.
5182 irpStack
->Parameters
.Scsi
.Srb
= (PVOID
)srb
;
5185 // Set up IRP Address.
5188 (VOID
)IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
5195 ToshibaProcessErrorCompletion(
5196 PDEVICE_OBJECT DeviceObject
,
5203 Routine Description:
5205 Completion routine for the ClassError routine to handle older Toshiba units
5206 that require setting the density code.
5210 DeviceObject - Supplies a pointer to the device object.
5212 Irp - Pointer to irp created to set the density code.
5214 Context - Supplies a pointer to the Mode Select Srb.
5219 STATUS_MORE_PROCESSING_REQUIRED
5225 PSCSI_REQUEST_BLOCK srb
= Context
;
5228 // Check for a frozen queue.
5231 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
5234 // Unfreeze the queue getting the device object from the context.
5237 ScsiClassReleaseQueue(DeviceObject
);
5241 // Free all of the allocations.
5244 ExFreePool(srb
->DataBuffer
);
5246 IoFreeMdl(Irp
->MdlAddress
);
5250 // Indicate the I/O system should stop processing the Irp completion.
5253 return STATUS_MORE_PROCESSING_REQUIRED
;
5258 ToshibaProcessError(
5259 PDEVICE_OBJECT DeviceObject
,
5260 PSCSI_REQUEST_BLOCK Srb
,
5267 Routine Description:
5269 This routine checks the type of error. If the error indicates a unit attention,
5270 the density code needs to be set via a Mode select command.
5274 DeviceObject - Supplies a pointer to the device object.
5276 Srb - Supplies a pointer to the failing Srb.
5289 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
5290 PCDROM_DATA cdData
= (PCDROM_DATA
)(deviceExtension
+1);
5291 PSENSE_DATA senseBuffer
= Srb
->SenseInfoBuffer
;
5292 PIO_STACK_LOCATION irpStack
;
5294 PSCSI_REQUEST_BLOCK srb
;
5300 if (!(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
)) {
5305 // The Toshiba's require the density code to be set on power up and media changes.
5308 if ((senseBuffer
->SenseKey
& 0xf) == SCSI_SENSE_UNIT_ATTENTION
) {
5311 irp
= IoAllocateIrp((CCHAR
)(deviceExtension
->DeviceObject
->StackSize
+1),
5318 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
5325 length
= sizeof(ERROR_RECOVERY_DATA
);
5326 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, length
);
5333 irp
->MdlAddress
= IoAllocateMdl(dataBuffer
,
5339 if (!irp
->MdlAddress
) {
5341 ExFreePool(dataBuffer
);
5350 MmBuildMdlForNonPagedPool(irp
->MdlAddress
);
5352 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
5354 srb
->DataBuffer
= dataBuffer
;
5355 cdb
= (PCDB
)srb
->Cdb
;
5361 IoSetNextIrpStackLocation(irp
);
5362 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
5363 irp
->IoStatus
.Information
= 0;
5365 irp
->UserBuffer
= NULL
;
5368 // Save the device object and irp in a private stack location.
5371 irpStack
= IoGetCurrentIrpStackLocation(irp
);
5372 irpStack
->DeviceObject
= deviceExtension
->DeviceObject
;
5375 // Construct the IRP stack for the lower level driver.
5378 irpStack
= IoGetNextIrpStackLocation(irp
);
5379 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
5380 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_OUT
;
5381 irpStack
->Parameters
.Scsi
.Srb
= srb
;
5383 IoSetCompletionRoutine(irp
,
5384 ToshibaProcessErrorCompletion
,
5390 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
5391 srb
->PathId
= deviceExtension
->PathId
;
5392 srb
->TargetId
= deviceExtension
->TargetId
;
5393 srb
->Lun
= deviceExtension
->Lun
;
5394 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
5395 srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
5396 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
5398 srb
->OriginalRequest
= irp
;
5399 srb
->SenseInfoBufferLength
= 0;
5402 // Set the transfer length.
5405 srb
->DataTransferLength
= length
;
5406 srb
->SrbFlags
= SRB_FLAGS_DATA_OUT
| SRB_FLAGS_DISABLE_AUTOSENSE
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
5410 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
5411 cdb
->MODE_SELECT
.PFBit
= 1;
5412 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)length
;
5415 // Copy the Mode page into the databuffer.
5418 RtlCopyMemory(srb
->DataBuffer
, &cdData
->u1
.Header
, length
);
5421 // Set the density code.
5424 ((PERROR_RECOVERY_DATA
)srb
->DataBuffer
)->BlockDescriptor
.DensityCode
= 0x83;
5426 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
5433 IN PDEVICE_OBJECT DeviceObject
5438 Routine Description:
5440 This routine determines if the cd is currently playing music.
5444 DeviceObject - Device object to test.
5448 TRUE if the device is playing music.
5452 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
5454 IO_STATUS_BLOCK ioStatus
;
5457 PSUB_Q_CURRENT_POSITION currentBuffer
;
5459 if (!PLAY_ACTIVE(deviceExtension
)) {
5463 currentBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, sizeof(SUB_Q_CURRENT_POSITION
));
5465 if (currentBuffer
== NULL
) {
5469 ((PCDROM_SUB_Q_DATA_FORMAT
) currentBuffer
)->Format
= IOCTL_CDROM_CURRENT_POSITION
;
5470 ((PCDROM_SUB_Q_DATA_FORMAT
) currentBuffer
)->Track
= 0;
5473 // Create notification event object to be used to signal the
5474 // request completion.
5477 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
5480 // Build the synchronous request to be sent to the port driver
5481 // to perform the request.
5484 irp
= IoBuildDeviceIoControlRequest(IOCTL_CDROM_READ_Q_CHANNEL
,
5485 deviceExtension
->DeviceObject
,
5487 sizeof(CDROM_SUB_Q_DATA_FORMAT
),
5489 sizeof(SUB_Q_CURRENT_POSITION
),
5495 ExFreePool(currentBuffer
);
5500 // Pass request to port driver and wait for request to complete.
5503 status
= IoCallDriver(deviceExtension
->DeviceObject
, irp
);
5505 if (status
== STATUS_PENDING
) {
5506 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
5507 status
= ioStatus
.Status
;
5510 if (!NT_SUCCESS(status
)) {
5511 ExFreePool(currentBuffer
);
5515 ExFreePool(currentBuffer
);
5517 return(PLAY_ACTIVE(deviceExtension
));
5521 IO_COMPLETION_ROUTINE CdRomMediaChangeCompletion
;
5524 CdRomMediaChangeCompletion(
5525 PDEVICE_OBJECT DeviceObject
,
5532 Routine Description:
5534 This routine handles the completion of the test unit ready irps
5535 used to determine if the media has changed. If the media has
5536 changed, this code signals the named event to wake up other
5537 system services that react to media change (aka AutoPlay).
5541 DeviceObject - the object for the completion
5542 Irp - the IRP being completed
5543 Context - the SRB from the IRP
5552 PSCSI_REQUEST_BLOCK srb
= (PSCSI_REQUEST_BLOCK
) Context
;
5553 PIO_STACK_LOCATION cdStack
= IoGetCurrentIrpStackLocation(Irp
);
5554 PIO_STACK_LOCATION irpNextStack
= IoGetNextIrpStackLocation(Irp
);
5555 PDEVICE_EXTENSION deviceExtension
;
5556 PDEVICE_EXTENSION physicalExtension
;
5557 PSENSE_DATA senseBuffer
;
5562 DeviceObject
= cdStack
->DeviceObject
;
5563 ASSERT(DeviceObject
);
5565 deviceExtension
= DeviceObject
->DeviceExtension
;
5566 physicalExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
5567 cddata
= (PCDROM_DATA
)(deviceExtension
+ 1);
5569 ASSERT(cddata
->MediaChangeIrp
== NULL
);
5572 // If the sense data field is valid, look for a media change.
5573 // otherwise this iteration of the polling will just assume nothing
5577 DebugPrint((3, "CdRomMediaChangeHandler: Completing Autorun Irp 0x%lx "
5579 Irp
, deviceExtension
->DeviceNumber
));
5581 if (srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) {
5582 if (srb
->SenseInfoBufferLength
>= FIELD_OFFSET(SENSE_DATA
, CommandSpecificInformation
)) {
5585 // See if this is a media change.
5588 senseBuffer
= srb
->SenseInfoBuffer
;
5589 if ((senseBuffer
->SenseKey
& 0x0f) == SCSI_SENSE_UNIT_ATTENTION
) {
5590 if (senseBuffer
->AdditionalSenseCode
== SCSI_ADSENSE_MEDIUM_CHANGED
) {
5592 DebugPrint((1, "CdRomMediaChangeCompletion: New media inserted "
5593 "into CdRom%d [irp = 0x%lx]\n",
5594 deviceExtension
->DeviceNumber
, Irp
));
5597 // Media change event occurred - signal the named event.
5600 KeSetEvent(deviceExtension
->MediaChangeEvent
,
5604 deviceExtension
->MediaChangeNoMedia
= FALSE
;
5608 if (DeviceObject
->Vpb
->Flags
& VPB_MOUNTED
) {
5611 // Must remember the media changed and force the
5612 // file system to verify on next access
5615 DeviceObject
->Flags
|= DO_VERIFY_VOLUME
;
5618 physicalExtension
->MediaChangeCount
++;
5620 } else if(((senseBuffer
->SenseKey
& 0x0f) == SCSI_SENSE_NOT_READY
)&&
5621 (senseBuffer
->AdditionalSenseCode
== SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
)&&
5622 (!deviceExtension
->MediaChangeNoMedia
)){
5625 // If there was no media in the device then signal the waiters if
5626 // we haven't already done so before.
5629 DebugPrint((1, "CdRomMediaChangeCompletion: No media in device"
5630 "CdRom%d [irp = 0x%lx]\n",
5631 deviceExtension
->DeviceNumber
, Irp
));
5633 KeSetEvent(deviceExtension
->MediaChangeEvent
,
5637 deviceExtension
->MediaChangeNoMedia
= TRUE
;
5641 } else if((srb
->SrbStatus
== SRB_STATUS_SUCCESS
)&&
5642 (deviceExtension
->MediaChangeNoMedia
)) {
5644 // We didn't have any media before and now the requests are succeeding
5645 // we probably missed the Media change somehow. Signal the change
5649 DebugPrint((1, "CdRomMediaChangeCompletion: Request completed normally"
5650 "for CdRom%d which was marked w/NoMedia [irp = 0x%lx]\n",
5651 deviceExtension
->DeviceNumber
, Irp
));
5653 KeSetEvent(deviceExtension
->MediaChangeEvent
,
5657 deviceExtension
->MediaChangeNoMedia
= FALSE
;
5661 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
5662 ScsiClassReleaseQueue(deviceExtension
->DeviceObject
);
5666 // Remember the IRP and SRB for use the next time.
5669 irpNextStack
->Parameters
.Scsi
.Srb
= srb
;
5670 cddata
->MediaChangeIrp
= Irp
;
5672 if (deviceExtension
->ClassError
) {
5678 // Throw away the status and retry values. Just give the error routine a chance
5679 // to do what it needs to.
5682 deviceExtension
->ClassError(DeviceObject
,
5688 IoStartNextPacket(DeviceObject
, FALSE
);
5690 return STATUS_MORE_PROCESSING_REQUIRED
;
5696 IN PDEVICE_OBJECT DeviceObject
,
5702 Routine Description:
5704 This routine handles the once per second timer provided by the
5705 Io subsystem. It is only used when the cdrom device itself is
5706 a candidate for autoplay support. It should never be called if
5707 the cdrom device is a changer device.
5711 DeviceObject - what to check.
5724 PLIST_ENTRY listEntry
;
5726 PIO_STACK_LOCATION irpStack
;
5727 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
5729 cddata
= (PCDROM_DATA
)(deviceExtension
+ 1);
5731 if (cddata
->MediaChange
) {
5732 if (cddata
->MediaChangeIrp
!= NULL
) {
5735 // Media change support is active and the IRP is waiting.
5736 // Decrement the timer.
5737 // There is no MP protection on the timer counter. This
5738 // code is the only code that will manipulate the timer
5739 // and only one instance of it should be running at any
5743 cddata
->MediaChangeCountDown
--;
5746 cddata
->MediaChangeIrpTimeInUse
= 0;
5747 cddata
->MediaChangeIrpLost
= FALSE
;
5750 if (!cddata
->MediaChangeCountDown
) {
5751 PSCSI_REQUEST_BLOCK srb
;
5752 PIO_STACK_LOCATION irpNextStack
;
5759 cddata
->MediaChangeCountDown
= MEDIA_CHANGE_DEFAULT_TIME
;
5762 // Prepare the IRP for the test unit ready
5765 irp
= cddata
->MediaChangeIrp
;
5766 cddata
->MediaChangeIrp
= NULL
;
5768 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
5769 irp
->IoStatus
.Information
= 0;
5771 irp
->UserBuffer
= NULL
;
5774 // If the irp is sent down when the volume needs to be
5775 // verified, CdRomUpdateGeometryCompletion won't complete
5776 // it since it's not associated with a thread. Marking
5777 // it to override the verify causes it always be sent
5778 // to the port driver
5781 irpStack
= IoGetCurrentIrpStackLocation(irp
);
5782 irpStack
->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
5784 irpNextStack
= IoGetNextIrpStackLocation(irp
);
5785 irpNextStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
5786 irpNextStack
->Parameters
.DeviceIoControl
.IoControlCode
=
5787 IOCTL_SCSI_EXECUTE_NONE
;
5790 // Prepare the SRB for execution.
5793 srb
= irpNextStack
->Parameters
.Scsi
.Srb
;
5794 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
5796 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
5797 srb
->PathId
= deviceExtension
->PathId
;
5798 srb
->TargetId
= deviceExtension
->TargetId
;
5799 srb
->Lun
= deviceExtension
->Lun
;
5800 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
5801 srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
|
5802 SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
5803 srb
->DataTransferLength
= 0;
5804 srb
->OriginalRequest
= irp
;
5806 RtlZeroMemory(srb
->SenseInfoBuffer
, SENSE_BUFFER_SIZE
);
5807 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
5809 cdb
= (PCDB
) &srb
->Cdb
[0];
5810 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_TEST_UNIT_READY
;
5811 cdb
->CDB6GENERIC
.LogicalUnitNumber
= srb
->Lun
;
5814 // Setup the IRP to perform a test unit ready.
5817 IoSetCompletionRoutine(irp
,
5818 CdRomMediaChangeCompletion
,
5825 // Issue the request.
5828 IoStartPacket(DeviceObject
, irp
, NULL
, NULL
);
5833 if(cddata
->MediaChangeIrpLost
== FALSE
) {
5834 if(cddata
->MediaChangeIrpTimeInUse
++ >
5835 MEDIA_CHANGE_TIMEOUT_TIME
) {
5837 DebugPrint((0, "CdRom%d: AutoPlay has lost it's irp and "
5838 "doesn't know where to find it. Leave it "
5839 "alone and it'll come home dragging it's "
5840 "stack behind it.\n",
5841 deviceExtension
->DeviceNumber
));
5842 cddata
->MediaChangeIrpLost
= TRUE
;
5851 // Process all generic timer IRPS in the timer list. As IRPs are pulled
5852 // off of the TimerIrpList they must be remembered in the first loop
5853 // if they are not sent to the lower driver. After all items have
5854 // been pulled off the list, it is possible to put the held IRPs back
5855 // into the TimerIrpList.
5859 if (IsListEmpty(&cddata
->TimerIrpList
)) {
5862 listEntry
= ExInterlockedRemoveHeadList(&cddata
->TimerIrpList
,
5863 &cddata
->TimerIrpSpinLock
);
5868 // There is something in the timer list. Pick up the IRP and
5869 // see if it is ready to be submitted.
5872 irp
= CONTAINING_RECORD(listEntry
, IRP
, Tail
.Overlay
.ListEntry
);
5873 irpStack
= IoGetCurrentIrpStackLocation(irp
);
5875 if (irpStack
->Parameters
.Others
.Argument3
) {
5879 // Decrement the countdown timer and put the IRP back in the list.
5882 count
= (ULONG_PTR
) irpStack
->Parameters
.Others
.Argument3
;
5884 irpStack
->Parameters
.Others
.Argument3
= (PVOID
) count
;
5886 ASSERT(irp
->AssociatedIrp
.MasterIrp
== NULL
);
5888 irp
->AssociatedIrp
.MasterIrp
= (PVOID
) heldIrpList
;
5895 // Submit this IRP to the lower driver. This IRP does not
5896 // need to be remembered here. It will be handled again when
5900 DebugPrint((1, "CdRomTickHandler: Reissuing request %lx (thread = %lx)\n", irp
, irp
->Tail
.Overlay
.Thread
));
5903 // feed this to the appropriate port driver
5906 IoCallDriver (deviceExtension
->PortDeviceObject
, irp
);
5911 // Pick up the next IRP from the timer list.
5914 listEntry
= ExInterlockedRemoveHeadList(&cddata
->TimerIrpList
,
5915 &cddata
->TimerIrpSpinLock
);
5919 // Move all held IRPs back onto the timer list.
5922 while (heldIrpList
) {
5925 // Save the single list pointer before queueing this IRP.
5928 nextIrp
= (PIRP
) heldIrpList
->AssociatedIrp
.MasterIrp
;
5929 heldIrpList
->AssociatedIrp
.MasterIrp
= NULL
;
5932 // Return the held IRP to the timer list.
5935 ExInterlockedInsertTailList(&cddata
->TimerIrpList
,
5936 &heldIrpList
->Tail
.Overlay
.ListEntry
,
5937 &cddata
->TimerIrpSpinLock
);
5940 // Continue processing the held IRPs
5943 heldIrpList
= nextIrp
;
5949 CdRomCheckRegistryForMediaChangeValue(
5950 IN PUNICODE_STRING RegistryPath
,
5951 IN ULONG DeviceNumber
5956 Routine Description:
5958 The user must specify that AutoPlay is to run on the platform
5959 by setting the registry value HKEY_LOCAL_MACHINE\System\CurrentControlSet\
5960 Services\Cdrom\Autorun:REG_DWORD:1.
5962 The user can override the global setting to enable or disable Autorun on a
5963 specific cdrom device by setting the key HKEY_LOCAL_MACHINE\System\
5964 CurrentControlSet\Services\Cdrom\Device<N>\Autorun:REG_DWORD to one or zero.
5965 (CURRENTLY UNIMPLEMENTED)
5967 If this registry value does not exist or contains the value zero then
5968 the timer to check for media change does not run.
5972 RegistryPath - pointer to the unicode string inside
5973 ...\CurrentControlSet\Services\Cdrom
5974 DeviceNumber - The number of the device object
5978 TRUE - Autorun is enabled.
5984 #define ITEMS_TO_QUERY 2 /* always 1 greater than what is searched */
5985 PRTL_QUERY_REGISTRY_TABLE parameters
= NULL
;
5993 ANSI_STRING paramNum
;
5995 UNICODE_STRING paramStr
;
5997 UNICODE_STRING paramSuffix
;
5998 UNICODE_STRING paramPath
;
5999 UNICODE_STRING paramDevPath
;
6002 // First append \Parameters to the passed in registry path
6005 RtlInitUnicodeString(¶mStr
, L
"\\Parameters");
6007 RtlInitUnicodeString(¶mPath
, NULL
);
6009 paramPath
.MaximumLength
= RegistryPath
->Length
+
6013 paramPath
.Buffer
= ExAllocatePool(PagedPool
, paramPath
.MaximumLength
);
6015 if(!paramPath
.Buffer
) {
6017 DebugPrint((1,"CdRomCheckRegAP: couldn't allocate paramPath\n"));
6022 RtlZeroMemory(paramPath
.Buffer
, paramPath
.MaximumLength
);
6023 RtlAppendUnicodeToString(¶mPath
, RegistryPath
->Buffer
);
6024 RtlAppendUnicodeToString(¶mPath
, paramStr
.Buffer
);
6026 DebugPrint((2, "CdRomCheckRegAP: paramPath [%d] = %ws\n",
6031 // build a counted ANSI string that contains
6032 // the suffix for the path
6035 sprintf(buf
, "\\Device%lu", DeviceNumber
);
6036 RtlInitAnsiString(¶mNum
, buf
);
6039 // Next convert this into a unicode string
6042 status
= RtlAnsiStringToUnicodeString(¶mSuffix
, ¶mNum
, TRUE
);
6044 if(!NT_SUCCESS(status
)) {
6045 DebugPrint((1,"CdRomCheckRegAP: couldn't convert paramNum to paramSuffix\n"));
6046 ExFreePool(paramPath
.Buffer
);
6050 RtlInitUnicodeString(¶mDevPath
, NULL
);
6053 // now build the device specific path
6056 paramDevPath
.MaximumLength
= paramPath
.Length
+
6057 paramSuffix
.Length
+
6059 paramDevPath
.Buffer
= ExAllocatePool(PagedPool
, paramDevPath
.MaximumLength
);
6061 if(!paramDevPath
.Buffer
) {
6062 RtlFreeUnicodeString(¶mSuffix
);
6063 ExFreePool(paramPath
.Buffer
);
6067 RtlZeroMemory(paramDevPath
.Buffer
, paramDevPath
.MaximumLength
);
6068 RtlAppendUnicodeToString(¶mDevPath
, paramPath
.Buffer
);
6069 RtlAppendUnicodeToString(¶mDevPath
, paramSuffix
.Buffer
);
6071 DebugPrint((2, "CdRomCheckRegAP: paramDevPath [%d] = %ws\n",
6075 parameters
= ExAllocatePool(NonPagedPool
,
6076 sizeof(RTL_QUERY_REGISTRY_TABLE
)*ITEMS_TO_QUERY
);
6081 // Check for the Autorun value.
6084 RtlZeroMemory(parameters
,
6085 (sizeof(RTL_QUERY_REGISTRY_TABLE
)*ITEMS_TO_QUERY
));
6087 parameters
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
6088 parameters
[0].Name
= L
"Autorun";
6089 parameters
[0].EntryContext
= &doRun
;
6090 parameters
[0].DefaultType
= REG_DWORD
;
6091 parameters
[0].DefaultData
= &zero
;
6092 parameters
[0].DefaultLength
= sizeof(ULONG
);
6094 status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
| RTL_REGISTRY_OPTIONAL
,
6095 RegistryPath
->Buffer
,
6100 DebugPrint((2, "CdRomCheckRegAP: cdrom/Autorun flag = %d\n", doRun
));
6102 RtlZeroMemory(parameters
,
6103 (sizeof(RTL_QUERY_REGISTRY_TABLE
)*ITEMS_TO_QUERY
));
6105 parameters
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
6106 parameters
[0].Name
= L
"Autorun";
6107 parameters
[0].EntryContext
= &tmp
;
6108 parameters
[0].DefaultType
= REG_DWORD
;
6109 parameters
[0].DefaultData
= &doRun
;
6110 parameters
[0].DefaultLength
= sizeof(ULONG
);
6112 status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
| RTL_REGISTRY_OPTIONAL
,
6118 DebugPrint((2, "CdRomCheckRegAP: cdrom/parameters/autorun flag = %d\n", tmp
));
6120 RtlZeroMemory(parameters
,
6121 (sizeof(RTL_QUERY_REGISTRY_TABLE
) * ITEMS_TO_QUERY
));
6123 parameters
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
6124 parameters
[0].Name
= L
"Autorun";
6125 parameters
[0].EntryContext
= &doRun
;
6126 parameters
[0].DefaultType
= REG_DWORD
;
6127 parameters
[0].DefaultData
= &tmp
;
6128 parameters
[0].DefaultLength
= sizeof(ULONG
);
6130 status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
| RTL_REGISTRY_OPTIONAL
,
6131 paramDevPath
.Buffer
,
6136 DebugPrint((1, "CdRomCheckRegAP: cdrom/parameters/device%d/autorun flag = %d\n", DeviceNumber
, doRun
));
6138 ExFreePool(parameters
);
6142 ExFreePool(paramPath
.Buffer
);
6143 ExFreePool(paramDevPath
.Buffer
);
6144 RtlFreeUnicodeString(¶mSuffix
);
6146 DebugPrint((1, "CdRomCheckRegAP: Autoplay for device %d is %s\n",
6148 (doRun
? "on" : "off")));
6161 IN PDEVICE_OBJECT DeviceObject
,
6168 Routine Description:
6170 This routine is called by DriverEntry to determine whether a Sanyo 3-CD
6171 changer device is present.
6175 DeviceObject - Supplies the device object for the 'real' device.
6181 TRUE - if an Atapi changer device is found.
6188 PCHAR inquiryBuffer
;
6189 IO_STATUS_BLOCK ioStatus
;
6191 PSCSI_ADAPTER_BUS_INFO adapterInfo
;
6193 PINQUIRYDATA inquiryData
;
6194 PSCSI_INQUIRY_DATA lunInfo
;
6196 inquiryBuffer
= ExAllocatePool(NonPagedPool
, 2048);
6197 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
6198 irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA
,
6211 status
= IoCallDriver(DeviceObject
, irp
);
6213 if (status
== STATUS_PENDING
) {
6214 KeWaitForSingleObject(&event
, Executive
, KernelMode
, FALSE
, NULL
);
6215 status
= ioStatus
.Status
;
6218 if (!NT_SUCCESS(status
)) {
6222 adapterInfo
= (PVOID
) inquiryBuffer
;
6224 for (scsiBus
=0; scsiBus
< (ULONG
)adapterInfo
->NumberOfBuses
; scsiBus
++) {
6227 // Get the SCSI bus scan data for this bus.
6230 lunInfo
= (PVOID
) (inquiryBuffer
+ adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
);
6234 if (lunInfo
->PathId
== PathId
&& lunInfo
->TargetId
== TargetId
) {
6236 inquiryData
= (PVOID
) lunInfo
->InquiryData
;
6238 if (RtlCompareMemory(inquiryData
->VendorId
, "TORiSAN CD-ROM CDR-C", 20) == 20) {
6239 ExFreePool(inquiryBuffer
);
6243 ExFreePool(inquiryBuffer
);
6247 if (!lunInfo
->NextInquiryDataOffset
) {
6251 lunInfo
= (PVOID
) (inquiryBuffer
+ lunInfo
->NextInquiryDataOffset
);
6255 ExFreePool(inquiryBuffer
);
6261 IsThisAnAtapiChanger(
6262 IN PDEVICE_OBJECT DeviceObject
,
6263 OUT PULONG DiscsPresent
6268 Routine Description:
6270 This routine is called by DriverEntry to determine whether an Atapi
6271 changer device is present.
6275 DeviceObject - Supplies the device object for the 'real' device.
6277 DiscsPresent - Supplies a pointer to the number of Discs supported by the changer.
6281 TRUE - if an Atapi changer device is found.
6286 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
6287 PMECHANICAL_STATUS_INFORMATION_HEADER mechanicalStatusBuffer
;
6289 SCSI_REQUEST_BLOCK srb
;
6290 PCDB cdb
= (PCDB
) &srb
.Cdb
[0];
6291 BOOLEAN retVal
= FALSE
;
6296 // Some devices can't handle 12 byte CDB's gracefully
6299 if(deviceExtension
->DeviceFlags
& DEV_NO_12BYTE_CDB
) {
6306 // Build and issue the mechanical status command.
6309 mechanicalStatusBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
6310 sizeof(MECHANICAL_STATUS_INFORMATION_HEADER
));
6312 if (!mechanicalStatusBuffer
) {
6317 // Build and send the Mechanism status CDB.
6320 RtlZeroMemory(&srb
, sizeof(srb
));
6323 srb
.TimeOutValue
= 20;
6325 cdb
->MECH_STATUS
.OperationCode
= SCSIOP_MECHANISM_STATUS
;
6326 cdb
->MECH_STATUS
.AllocationLength
[1] = sizeof(MECHANICAL_STATUS_INFORMATION_HEADER
);
6328 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
6330 mechanicalStatusBuffer
,
6331 sizeof(MECHANICAL_STATUS_INFORMATION_HEADER
),
6335 if (status
== STATUS_SUCCESS
) {
6338 // Indicate number of slots available
6341 *DiscsPresent
= mechanicalStatusBuffer
->NumberAvailableSlots
;
6342 if (*DiscsPresent
> 1) {
6347 // If only one disc, no need for this driver.
6355 // Device doesn't support this command.
6361 ExFreePool(mechanicalStatusBuffer
);
6369 IsThisAMultiLunDevice(
6370 IN PDEVICE_OBJECT DeviceObject
,
6371 IN PDEVICE_OBJECT PortDeviceObject
6375 Routine Description:
6377 This routine is called to determine whether a multi-lun
6382 DeviceObject - Supplies the device object for the 'real' device.
6386 TRUE - if a Multi-lun device is found.
6391 PSCSI_INQUIRY_DATA lunInfo
;
6392 PSCSI_ADAPTER_BUS_INFO adapterInfo
;
6393 PDEVICE_EXTENSION deviceExtension
= (PDEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
6394 PINQUIRYDATA inquiryData
;
6399 status
= ScsiClassGetInquiryData(PortDeviceObject
, (PSCSI_ADAPTER_BUS_INFO
*) &buffer
);
6401 if (!NT_SUCCESS(status
)) {
6402 DebugPrint((1,"IsThisAMultiLunDevice: ScsiClassGetInquiryData failed\n"));
6406 adapterInfo
= (PVOID
) buffer
;
6409 // For each SCSI bus this adapter supports ...
6412 for (scsiBus
=0; scsiBus
< adapterInfo
->NumberOfBuses
; scsiBus
++) {
6415 // Get the SCSI bus scan data for this bus.
6418 lunInfo
= (PVOID
) (buffer
+ adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
);
6420 while (adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
) {
6422 inquiryData
= (PVOID
)lunInfo
->InquiryData
;
6424 if ((lunInfo
->PathId
== deviceExtension
->PathId
) &&
6425 (lunInfo
->TargetId
== deviceExtension
->TargetId
) &&
6426 (inquiryData
->DeviceType
== READ_ONLY_DIRECT_ACCESS_DEVICE
)) {
6428 DebugPrint((1,"IsThisAMultiLunDevice: Vendor string is %.24s\n",
6429 inquiryData
->VendorId
));
6432 // If this device has more than one cdrom-type lun then we
6433 // won't support autoplay on it
6443 // Get next LunInfo.
6446 if (lunInfo
->NextInquiryDataOffset
== 0) {
6450 lunInfo
= (PVOID
) (buffer
+ lunInfo
->NextInquiryDataOffset
);
6459 IO_COMPLETION_ROUTINE CdRomUpdateGeometryCompletion
;
6462 CdRomUpdateGeometryCompletion(
6463 PDEVICE_OBJECT DeviceObject
,
6470 Routine Description:
6472 This routine andles the completion of the test unit ready irps
6473 used to determine if the media has changed. If the media has
6474 changed, this code signals the named event to wake up other
6475 system services that react to media change (aka AutoPlay).
6479 DeviceObject - the object for the completion
6480 Irp - the IRP being completed
6481 Context - the SRB from the IRP
6490 PSCSI_REQUEST_BLOCK srb
= (PSCSI_REQUEST_BLOCK
) Context
;
6491 PREAD_CAPACITY_DATA readCapacityBuffer
;
6492 PDEVICE_EXTENSION deviceExtension
;
6493 PIO_STACK_LOCATION irpStack
;
6496 ULONG_PTR retryCount
;
6502 // Get items saved in the private IRP stack location.
6505 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
6506 retryCount
= (ULONG_PTR
) irpStack
->Parameters
.Others
.Argument1
;
6507 originalIrp
= (PIRP
) irpStack
->Parameters
.Others
.Argument2
;
6509 if (!DeviceObject
) {
6510 DeviceObject
= irpStack
->DeviceObject
;
6512 ASSERT(DeviceObject
);
6514 deviceExtension
= DeviceObject
->DeviceExtension
;
6515 cddata
= (PCDROM_DATA
) (deviceExtension
+ 1);
6516 readCapacityBuffer
= srb
->DataBuffer
;
6518 if ((NT_SUCCESS(Irp
->IoStatus
.Status
)) && (SRB_STATUS(srb
->SrbStatus
) == SRB_STATUS_SUCCESS
)) {
6522 DebugPrint((2, "CdRomUpdateCapacityCompletion: [%lx] successful completion of buddy-irp %lx\n", originalIrp
, Irp
));
6524 // Copy sector size from read capacity buffer to device extension
6525 // in reverse byte order.
6528 from
= (PFOUR_BYTE
) &readCapacityBuffer
->BytesPerBlock
;
6529 to
= (PFOUR_BYTE
) &deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
;
6530 to
->Byte0
= from
->Byte3
;
6531 to
->Byte1
= from
->Byte2
;
6532 to
->Byte2
= from
->Byte1
;
6533 to
->Byte3
= from
->Byte0
;
6536 // Using the new BytesPerBlock, calculate and store the SectorShift.
6539 WHICH_BIT(deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
, deviceExtension
->SectorShift
);
6542 // Copy last sector in reverse byte order.
6545 from
= (PFOUR_BYTE
) &readCapacityBuffer
->LogicalBlockAddress
;
6546 to
= (PFOUR_BYTE
) &lastSector
;
6547 to
->Byte0
= from
->Byte3
;
6548 to
->Byte1
= from
->Byte2
;
6549 to
->Byte2
= from
->Byte1
;
6550 to
->Byte3
= from
->Byte0
;
6551 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(lastSector
+ 1);
6554 // Calculate number of cylinders.
6557 deviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
= (LONGLONG
)((lastSector
+ 1)/(32 * 64));
6558 deviceExtension
->PartitionLength
.QuadPart
=
6559 (deviceExtension
->PartitionLength
.QuadPart
<< deviceExtension
->SectorShift
);
6560 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= RemovableMedia
;
6563 // Assume sectors per track are 32;
6566 deviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
= 32;
6569 // Assume tracks per cylinder (number of heads) is 64.
6572 deviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
= 64;
6576 DebugPrint((1, "CdRomUpdateCapacityCompletion: [%lx] unsuccessful completion of buddy-irp %lx (status - %lx)\n", originalIrp
, Irp
, Irp
->IoStatus
.Status
));
6578 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
6579 ScsiClassReleaseQueue(DeviceObject
);
6582 retry
= ScsiClassInterpretSenseInfo(DeviceObject
,
6593 DebugPrint((1, "CdRomUpdateCapacityCompletion: [%lx] Retrying request %lx .. thread is %lx\n", originalIrp
, Irp
, Irp
->Tail
.Overlay
.Thread
));
6595 // set up a one shot timer to get this process started over
6598 irpStack
->Parameters
.Others
.Argument1
= (PVOID
) retryCount
;
6599 irpStack
->Parameters
.Others
.Argument2
= (PVOID
) originalIrp
;
6600 irpStack
->Parameters
.Others
.Argument3
= (PVOID
) 2;
6603 // Setup the IRP to be submitted again in the timer routine.
6606 irpStack
= IoGetNextIrpStackLocation(Irp
);
6607 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
6608 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
6609 irpStack
->Parameters
.Scsi
.Srb
= srb
;
6610 IoSetCompletionRoutine(Irp
,
6611 CdRomUpdateGeometryCompletion
,
6618 // Set up the SRB for read capacity.
6621 srb
->CdbLength
= 10;
6622 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
6623 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
6625 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
6626 srb
->PathId
= deviceExtension
->PathId
;
6627 srb
->TargetId
= deviceExtension
->TargetId
;
6628 srb
->Lun
= deviceExtension
->Lun
;
6629 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
6630 srb
->SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
6631 srb
->DataTransferLength
= sizeof(READ_CAPACITY_DATA
);
6637 cdb
= (PCDB
) &srb
->Cdb
[0];
6638 cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
6639 cdb
->CDB10
.LogicalUnitNumber
= deviceExtension
->Lun
;
6642 // Requests queued onto this list will be sent to the
6643 // lower level driver during CdRomTickHandler
6646 ExInterlockedInsertHeadList(&cddata
->TimerIrpList
,
6647 &Irp
->Tail
.Overlay
.ListEntry
,
6648 &cddata
->TimerIrpSpinLock
);
6650 return STATUS_MORE_PROCESSING_REQUIRED
;
6654 // This has been bounced for a number of times. Error the
6655 // original request.
6658 originalIrp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
6659 RtlZeroMemory(deviceExtension
->DiskGeometry
, sizeof(DISK_GEOMETRY_EX
));
6660 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= 2048;
6661 deviceExtension
->SectorShift
= 11;
6662 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(0x7fffffff);
6663 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= RemovableMedia
;
6668 // Set up reasonable defaults
6671 RtlZeroMemory(deviceExtension
->DiskGeometry
, sizeof(DISK_GEOMETRY_EX
));
6672 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= 2048;
6673 deviceExtension
->SectorShift
= 11;
6674 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(0x7fffffff);
6675 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= RemovableMedia
;
6680 // Free resources held.
6683 ExFreePool(srb
->SenseInfoBuffer
);
6684 ExFreePool(srb
->DataBuffer
);
6686 if (Irp
->MdlAddress
) {
6687 IoFreeMdl(Irp
->MdlAddress
);
6690 if (originalIrp
->Tail
.Overlay
.Thread
) {
6692 DebugPrint((2, "CdRomUpdateCapacityCompletion: [%lx] completing original IRP\n", originalIrp
));
6693 IoCompleteRequest(originalIrp
, IO_DISK_INCREMENT
);
6696 DebugPrint((1, "CdRomUpdateCapacityCompletion: [%lx] original irp has "
6703 // It's now safe to either start the next request or let the waiting ioctl
6704 // request continue along it's merry way
6707 IoStartNextPacket(DeviceObject
, FALSE
);
6709 return STATUS_MORE_PROCESSING_REQUIRED
;
6714 CdRomUpdateCapacity(
6715 IN PDEVICE_EXTENSION DeviceExtension
,
6716 IN PIRP IrpToComplete
,
6717 IN OPTIONAL PKEVENT IoctlEvent
6722 Routine Description:
6724 This routine updates the capacity of the disk as recorded in the device extension.
6725 It also completes the IRP given with STATUS_VERIFY_REQUIRED. This routine is called
6726 when a media change has occurred and it is necessary to determine the capacity of the
6727 new media prior to the next access.
6731 DeviceExtension - the device to update
6732 IrpToComplete - the request that needs to be completed when done.
6743 PSCSI_REQUEST_BLOCK srb
;
6744 PREAD_CAPACITY_DATA capacityBuffer
;
6745 PIO_STACK_LOCATION irpStack
;
6748 irp
= IoAllocateIrp((CCHAR
)(DeviceExtension
->DeviceObject
->StackSize
+1),
6753 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
6755 capacityBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
6756 sizeof(READ_CAPACITY_DATA
));
6758 if (capacityBuffer
) {
6761 senseBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
6765 irp
->MdlAddress
= IoAllocateMdl(capacityBuffer
,
6766 sizeof(READ_CAPACITY_DATA
),
6771 if (irp
->MdlAddress
) {
6774 // Have all resources. Set up the IRP to send for the capacity.
6777 IoSetNextIrpStackLocation(irp
);
6778 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
6779 irp
->IoStatus
.Information
= 0;
6781 irp
->UserBuffer
= NULL
;
6784 // Save the device object and retry count in a private stack location.
6787 irpStack
= IoGetCurrentIrpStackLocation(irp
);
6788 irpStack
->DeviceObject
= DeviceExtension
->DeviceObject
;
6789 irpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
6790 irpStack
->Parameters
.Others
.Argument2
= (PVOID
) IrpToComplete
;
6793 // Construct the IRP stack for the lower level driver.
6796 irpStack
= IoGetNextIrpStackLocation(irp
);
6797 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
6798 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
6799 irpStack
->Parameters
.Scsi
.Srb
= srb
;
6800 IoSetCompletionRoutine(irp
,
6801 CdRomUpdateGeometryCompletion
,
6810 MmBuildMdlForNonPagedPool(irp
->MdlAddress
);
6814 // Set up the SRB for read capacity.
6817 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
6818 RtlZeroMemory(senseBuffer
, SENSE_BUFFER_SIZE
);
6819 srb
->CdbLength
= 10;
6820 srb
->TimeOutValue
= DeviceExtension
->TimeOutValue
;
6821 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
6823 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
6824 srb
->PathId
= DeviceExtension
->PathId
;
6825 srb
->TargetId
= DeviceExtension
->TargetId
;
6826 srb
->Lun
= DeviceExtension
->Lun
;
6827 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
6828 srb
->SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
6829 srb
->DataBuffer
= capacityBuffer
;
6830 srb
->DataTransferLength
= sizeof(READ_CAPACITY_DATA
);
6831 srb
->OriginalRequest
= irp
;
6832 srb
->SenseInfoBuffer
= senseBuffer
;
6833 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
6839 cdb
= (PCDB
) &srb
->Cdb
[0];
6840 cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
6841 cdb
->CDB10
.LogicalUnitNumber
= DeviceExtension
->Lun
;
6844 // Set the return value in the IRP that will be completed
6845 // upon completion of the read capacity.
6848 IrpToComplete
->IoStatus
.Status
= STATUS_VERIFY_REQUIRED
;
6849 IoMarkIrpPending(IrpToComplete
);
6851 IoCallDriver(DeviceExtension
->PortDeviceObject
, irp
);
6854 // status is not checked because the completion routine for this
6855 // IRP will always get called and it will free the resources.
6858 return STATUS_PENDING
;
6861 ExFreePool(senseBuffer
);
6862 ExFreePool(capacityBuffer
);
6867 ExFreePool(capacityBuffer
);
6880 return STATUS_INSUFFICIENT_RESOURCES
;
6885 CdRomClassIoctlCompletion(
6886 IN PDEVICE_OBJECT DeviceObject
,
6893 Routine Description:
6895 This routine signals the event used by CdRomDeviceControl to synchronize
6896 class driver (and lower level driver) ioctls with cdrom's startio routine.
6897 The irp completion is short-circuited so that CdRomDeviceControl can
6898 reissue it once it wakes up.
6902 DeviceObject - the device object
6903 Irp - the request we are synchronizing
6904 Context - a PKEVENT that we need to signal
6913 PKEVENT syncEvent
= (PKEVENT
) Context
;
6915 DebugPrint((2, "CdRomClassIoctlCompletion: setting event for irp %#08lx\n",
6919 KeSetEvent(syncEvent
, IO_DISK_INCREMENT
, FALSE
);
6921 return STATUS_MORE_PROCESSING_REQUIRED
;