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
14 #define CDB12GENERIC_LENGTH 12
16 typedef struct _XA_CONTEXT
{
19 // Pointer to the device object.
22 PDEVICE_OBJECT DeviceObject
;
25 // Pointer to the original request when
26 // a mode select must be sent.
32 // Pointer to the mode select srb.
35 PSCSI_REQUEST_BLOCK Srb
;
36 } XA_CONTEXT
, *PXA_CONTEXT
;
38 typedef struct _ERROR_RECOVERY_DATA
{
39 MODE_PARAMETER_HEADER Header
;
40 MODE_PARAMETER_BLOCK BlockDescriptor
;
41 MODE_READ_RECOVERY_PAGE ReadRecoveryPage
;
42 } ERROR_RECOVERY_DATA
, *PERROR_RECOVERY_DATA
;
44 typedef struct _ERROR_RECOVERY_DATA10
{
45 MODE_PARAMETER_HEADER10 Header10
;
46 MODE_PARAMETER_BLOCK BlockDescriptor10
;
47 MODE_READ_RECOVERY_PAGE ReadRecoveryPage10
;
48 } ERROR_RECOVERY_DATA10
, *PERROR_RECOVERY_DATA10
;
51 // CdRom specific addition to device extension.
54 typedef struct _CDROM_DATA
{
57 // Indicates whether an audio play operation
58 // is currently being performed.
64 // Indicates whether the blocksize used for user data
71 // Indicates whether 6 or 10 byte mode sense/select
78 // Storage for the error recovery page. This is used
79 // as an easy method to switch block sizes.
83 ERROR_RECOVERY_DATA u1
;
84 ERROR_RECOVERY_DATA10 u2
;
89 // Pointer to the original irp for the raw read.
95 // Used to protect accesses to the RawAccess flag.
98 KSPIN_LOCK FormSpinLock
;
101 // Even if media change support is requested, there are some devices
102 // that are not supported. This flag will indicate that such a device
103 // is present when it is FALSE.
106 BOOLEAN MediaChangeSupported
;
109 // The media change event is being supported. The media change timer
110 // should be running whenever this is true.
116 // The timer value to support media change events. This is a countdown
117 // value used to determine when to poll the device for a media change.
118 // The max value for the timer is 255 seconds.
121 UCHAR MediaChangeCountDown
;
125 // Second timer to keep track of how long the media change IRP has been
126 // in use. If this value exceeds the timeout (#defined) then we should
127 // print out a message to the user and set the MediaChangeIrpLost flag
130 SHORT MediaChangeIrpTimeInUse
;
133 // Set by CdRomTickHandler when we determine that the media change irp has
137 BOOLEAN MediaChangeIrpLost
;
140 UCHAR PadReserve
; // use this for new flags.
143 // An IRP is allocated and kept for the duration that media change
144 // detection is in effect. If this is NULL and MediaChange is TRUE,
145 // the detection is in progress. This should always be NULL when
146 // MediaChange is FALSE.
152 // The timer work list is a collection of IRPS that are prepared for
153 // submission, but need to allow some time to pass before they are
157 LIST_ENTRY TimerIrpList
;
158 KSPIN_LOCK TimerIrpSpinLock
;
160 } CDROM_DATA
, *PCDROM_DATA
;
162 #define DEVICE_EXTENSION_SIZE sizeof(DEVICE_EXTENSION) + sizeof(CDROM_DATA)
163 #define SCSI_CDROM_TIMEOUT 10
164 #define SCSI_CHANGER_BONUS_TIMEOUT 10
165 #define HITACHI_MODE_DATA_SIZE 12
166 #define MODE_DATA_SIZE 64
167 #define RAW_SECTOR_SIZE 2352
168 #define COOKED_SECTOR_SIZE 2048
169 #define MEDIA_CHANGE_DEFAULT_TIME 4
170 #define CDROM_SRB_LIST_SIZE 4
176 // Used to detect the loss of the autorun irp. The driver prints out a message
177 // (debug level 0) if this timeout ever occurs
179 #define MEDIA_CHANGE_TIMEOUT_TIME 300
183 #define PLAY_ACTIVE(DeviceExtension) (((PCDROM_DATA)(DeviceExtension + 1))->PlayActive)
185 #define MSF_TO_LBA(Minutes,Seconds,Frames) \
186 (ULONG)((60 * 75 * (Minutes)) + (75 * (Seconds)) + ((Frames) - 150))
188 #define LBA_TO_MSF(Lba,Minutes,Seconds,Frames) \
190 (Minutes) = (UCHAR)(Lba / (60 * 75)); \
191 (Seconds) = (UCHAR)((Lba % (60 * 75)) / 75); \
192 (Frames) = (UCHAR)((Lba % (60 * 75)) % 75); \
195 #define DEC_TO_BCD(x) (((x / 10) << 4) + (x % 10))
198 // Define flags for XA, CDDA, and Mode Select/Sense
201 #define XA_USE_6_BYTE 0x01
202 #define XA_USE_10_BYTE 0x02
203 #define XA_USE_READ_CD 0x04
204 #define XA_NOT_SUPPORTED 0x08
206 #define PLEXTOR_CDDA 0x10
207 #define NEC_CDDA 0x20
210 // Sector types for READ_CD
214 #define CD_DA_SECTOR 1
215 #define YELLOW_MODE1_SECTOR 2
216 #define YELLOW_MODE2_SECTOR 3
217 #define FORM2_MODE1_SECTOR 4
218 #define FORM2_MODE2_SECTOR 5
222 #ifdef ExAllocatePool
223 #undef ExAllocatePool
225 #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'CscS')
231 IN PDRIVER_OBJECT DriverObject
,
232 IN PUNICODE_STRING RegistryPath
237 ScsiCdRomFindDevices(
238 IN PDRIVER_OBJECT DriverObject
,
239 IN PUNICODE_STRING RegistryPath
,
240 IN PCLASS_INIT_DATA InitializationData
,
241 IN PDEVICE_OBJECT PortDeviceObject
,
248 IN PDEVICE_OBJECT DeviceObject
,
254 ScsiCdRomReadVerification(
255 IN PDEVICE_OBJECT DeviceObject
,
262 IN PDEVICE_OBJECT DeviceObject
,
264 IN PIRP OriginalRequest
270 IN PDEVICE_OBJECT DeviceObject
,
274 IO_COMPLETION_ROUTINE CdRomDeviceControlCompletion
;
277 CdRomDeviceControlCompletion(
278 IN PDEVICE_OBJECT DeviceObject
,
283 IO_COMPLETION_ROUTINE CdRomSetVolumeIntermediateCompletion
;
286 CdRomSetVolumeIntermediateCompletion(
287 IN PDEVICE_OBJECT DeviceObject
,
292 IO_COMPLETION_ROUTINE CdRomSwitchModeCompletion
;
295 CdRomSwitchModeCompletion(
296 IN PDEVICE_OBJECT DeviceObject
,
301 IO_COMPLETION_ROUTINE CdRomXACompletion
;
305 IN PDEVICE_OBJECT DeviceObject
,
310 IO_COMPLETION_ROUTINE CdRomClassIoctlCompletion
;
313 CdRomClassIoctlCompletion(
314 IN PDEVICE_OBJECT DeviceObject
,
322 IN PDEVICE_OBJECT DeviceObject
,
329 IN PDEVICE_OBJECT DeviceObject
,
335 CdRomCheckRegistryForMediaChangeValue(
336 IN PUNICODE_STRING RegistryPath
,
337 IN ULONG DeviceNumber
343 IN PDEVICE_EXTENSION DeviceExtension
,
344 IN PIRP IrpToComplete
,
345 IN OPTIONAL PKEVENT IoctlEvent
350 CreateCdRomDeviceObject(
351 IN PDRIVER_OBJECT DriverObject
,
352 IN PDEVICE_OBJECT PortDeviceObject
,
354 IN PULONG DeviceCount
,
355 PIO_SCSI_CAPABILITIES PortCapabilities
,
356 IN PSCSI_INQUIRY_DATA LunInfo
,
357 IN PCLASS_INIT_DATA InitializationData
,
358 IN PUNICODE_STRING RegistryPath
364 PDEVICE_OBJECT DeviceObject
,
365 PINQUIRYDATA InquiryData
,
366 PIO_SCSI_CAPABILITIES PortCapabilities
372 IN PDEVICE_OBJECT DeviceObject
378 PDEVICE_OBJECT DeviceObject
,
379 PSCSI_REQUEST_BLOCK Srb
,
384 IO_COMPLETION_ROUTINE ToshibaProcessErrorCompletion
;
388 PDEVICE_OBJECT DeviceObject
,
389 PSCSI_REQUEST_BLOCK Srb
,
396 IsThisAnAtapiChanger(
397 IN PDEVICE_OBJECT DeviceObject
,
398 OUT PULONG DiscsPresent
404 IN PDEVICE_OBJECT DeviceObject
,
411 IsThisAMultiLunDevice(
412 IN PDEVICE_OBJECT DeviceObject
,
413 IN PDEVICE_OBJECT PortDeviceObject
418 CdRomCreateNamedEvent(
419 IN PDEVICE_EXTENSION DeviceExtension
,
420 IN ULONG DeviceNumber
427 IN UNICODE_STRING ScsiUnicodeString
[],
428 OUT PUCHAR IntermediateController
433 #pragma alloc_text(PAGE, DriverEntry)
434 #pragma alloc_text(PAGE, ScsiCdRomFindDevices)
435 #pragma alloc_text(PAGE, CreateCdRomDeviceObject)
436 #pragma alloc_text(PAGE, ScanForSpecial)
437 //#pragma alloc_text(PAGE, CdRomDeviceControl)
438 #pragma alloc_text(PAGE, HitachProcessError)
439 #pragma alloc_text(PAGE, CdRomIsPlayActive)
440 #pragma alloc_text(PAGE, ScsiCdRomReadVerification)
441 #pragma alloc_text(INIT, CdRomCheckRegistryForMediaChangeValue)
442 #pragma alloc_text(INIT, IsThisAnAtapiChanger)
443 #pragma alloc_text(INIT, IsThisASanyo)
444 #pragma alloc_text(INIT, IsThisAMultiLunDevice)
445 #pragma alloc_text(INIT, CdRomCreateNamedEvent)
447 #pragma alloc_text(PAGE, FindScsiAdapter)
456 IN PDRIVER_OBJECT DriverObject
,
457 IN PUNICODE_STRING RegistryPath
464 This routine initializes the cdrom class driver.
468 DriverObject - Pointer to driver object created by system.
470 RegistryPath - Pointer to the name of the services node for this driver.
474 The function value is the final status from the initialization operation.
479 CLASS_INIT_DATA InitializationData
;
482 return STATUS_NO_SUCH_DEVICE
;
489 RtlZeroMemory (&InitializationData
, sizeof(CLASS_INIT_DATA
));
495 InitializationData
.InitializationDataSize
= sizeof(CLASS_INIT_DATA
);
496 InitializationData
.DeviceExtensionSize
= DEVICE_EXTENSION_SIZE
;
498 InitializationData
.DeviceType
= FILE_DEVICE_CD_ROM
;
499 InitializationData
.DeviceCharacteristics
= FILE_REMOVABLE_MEDIA
| FILE_READ_ONLY_DEVICE
;
505 InitializationData
.ClassReadWriteVerification
= ScsiCdRomReadVerification
;
506 InitializationData
.ClassDeviceControl
= CdRomDeviceControl
;
507 InitializationData
.ClassFindDevices
= ScsiCdRomFindDevices
;
508 InitializationData
.ClassShutdownFlush
= NULL
;
509 InitializationData
.ClassCreateClose
= NULL
;
510 InitializationData
.ClassStartIo
= ScsiCdRomStartIo
;
513 // Call the class init routine
516 return ScsiClassInitialize( DriverObject
, RegistryPath
, &InitializationData
);
518 } // end DriverEntry()
522 ScsiCdRomFindDevices(
523 IN PDRIVER_OBJECT DriverObject
,
524 IN PUNICODE_STRING RegistryPath
,
525 IN PCLASS_INIT_DATA InitializationData
,
526 IN PDEVICE_OBJECT PortDeviceObject
,
534 Connect to SCSI port driver. Get adapter capabilities and
535 SCSI bus configuration information. Search inquiry data
536 for CDROM devices to process.
540 DriverObject - CDROM class driver object.
541 PortDeviceObject - SCSI port driver device object.
542 PortNumber - The system ordinal for this scsi adapter.
546 TRUE if CDROM device present on this SCSI adapter.
551 PIO_SCSI_CAPABILITIES portCapabilities
;
554 PSCSI_INQUIRY_DATA lunInfo
;
555 PSCSI_ADAPTER_BUS_INFO adapterInfo
;
556 PINQUIRYDATA inquiryData
;
559 BOOLEAN foundDevice
= FALSE
;
562 // Call port driver to get adapter capabilities.
565 status
= ScsiClassGetCapabilities(PortDeviceObject
, &portCapabilities
);
567 if (!NT_SUCCESS(status
)) {
568 DebugPrint((1,"FindScsiDevices: ScsiClassGetCapabilities failed\n"));
573 // Call port driver to get inquiry information to find cdroms.
576 status
= ScsiClassGetInquiryData(PortDeviceObject
, (PSCSI_ADAPTER_BUS_INFO
*) &buffer
);
578 if (!NT_SUCCESS(status
)) {
579 DebugPrint((1,"FindScsiDevices: ScsiClassGetInquiryData failed\n"));
584 // Get the address of the count of the number of cdroms already initialized.
587 cdRomCount
= &IoGetConfigurationInformation()->CdRomCount
;
588 adapterInfo
= (PVOID
) buffer
;
591 // For each SCSI bus this adapter supports ...
594 for (scsiBus
=0; scsiBus
< adapterInfo
->NumberOfBuses
; scsiBus
++) {
597 // Get the SCSI bus scan data for this bus.
600 lunInfo
= (PVOID
) (buffer
+ adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
);
603 // Search list for unclaimed disk devices.
606 while (adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
) {
608 inquiryData
= (PVOID
)lunInfo
->InquiryData
;
610 if ((inquiryData
->DeviceType
== READ_ONLY_DIRECT_ACCESS_DEVICE
) &&
611 (inquiryData
->DeviceTypeQualifier
== 0) &&
612 (!lunInfo
->DeviceClaimed
)) {
614 DebugPrint((1,"FindScsiDevices: Vendor string is %.24s\n",
615 inquiryData
->VendorId
));
618 // Create device objects for cdrom
621 status
= CreateCdRomDeviceObject(DriverObject
,
630 if (NT_SUCCESS(status
)) {
633 // Increment system cdrom device count.
639 // Indicate that a cdrom device was found.
650 if (lunInfo
->NextInquiryDataOffset
== 0) {
654 lunInfo
= (PVOID
) (buffer
+ lunInfo
->NextInquiryDataOffset
);
663 } // end FindScsiCdRoms()
667 CdRomCreateNamedEvent(
668 IN PDEVICE_EXTENSION DeviceExtension
,
669 IN ULONG DeviceNumber
676 Create the named synchronization event for notification of media change
677 events to the system. The event is reset before this function returns.
681 DeviceExtension - the device extension pointer for storage of the event pointer.
690 UNICODE_STRING unicodeString
;
691 OBJECT_ATTRIBUTES objectAttributes
;
692 CCHAR eventNameBuffer
[MAXIMUM_FILENAME_LENGTH
];
693 STRING eventNameString
;
698 sprintf(eventNameBuffer
,"\\Device\\MediaChangeEvent%ld",
701 RtlInitString(&eventNameString
,
704 status
= RtlAnsiStringToUnicodeString(&unicodeString
,
708 if (!NT_SUCCESS(status
)) {
712 InitializeObjectAttributes(&objectAttributes
,
714 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
718 DeviceExtension
->MediaChangeEvent
= IoCreateSynchronizationEvent(&unicodeString
,
720 DeviceExtension
->MediaChangeEventHandle
= handle
;
722 KeClearEvent(DeviceExtension
->MediaChangeEvent
);
724 RtlFreeUnicodeString(&unicodeString
);
729 CreateCdRomDeviceObject(
730 IN PDRIVER_OBJECT DriverObject
,
731 IN PDEVICE_OBJECT PortDeviceObject
,
733 IN PULONG DeviceCount
,
734 IN PIO_SCSI_CAPABILITIES PortCapabilities
,
735 IN PSCSI_INQUIRY_DATA LunInfo
,
736 IN PCLASS_INIT_DATA InitializationData
,
737 IN PUNICODE_STRING RegistryPath
744 This routine creates an object for the device and then calls the
745 SCSI port driver for media capacity and sector size.
749 DriverObject - Pointer to driver object created by system.
750 PortDeviceObject - to connect to SCSI port driver.
751 DeviceCount - Number of previously installed CDROMs.
752 PortCapabilities - Pointer to structure returned by SCSI port
753 driver describing adapter capabilites (and limitations).
754 LunInfo - Pointer to configuration information for this device.
762 CHAR ntNameBuffer
[64];
764 BOOLEAN changerDevice
;
765 SCSI_REQUEST_BLOCK srb
;
769 PVOID senseData
= NULL
;
770 PDEVICE_OBJECT deviceObject
= NULL
;
771 PDEVICE_EXTENSION deviceExtension
= NULL
;
776 BOOLEAN srbListInitialized
= FALSE
;
779 // Claim the device. Note that any errors after this
780 // will goto the generic handler, where the device will
784 status
= ScsiClassClaimDevice(PortDeviceObject
,
789 if (!NT_SUCCESS(status
)) {
794 // Create device object for this device.
797 sprintf(ntNameBuffer
,
798 "\\Device\\CdRom%lu",
801 status
= ScsiClassCreateDeviceObject(DriverObject
,
807 if (!NT_SUCCESS(status
)) {
808 DebugPrint((1,"CreateCdRomDeviceObjects: Can not create device %s\n",
811 goto CreateCdRomDeviceObjectExit
;
815 // Indicate that IRPs should include MDLs.
818 deviceObject
->Flags
|= DO_DIRECT_IO
;
821 // Set up required stack size in device object.
824 deviceObject
->StackSize
= PortDeviceObject
->StackSize
+ 2;
826 deviceExtension
= deviceObject
->DeviceExtension
;
829 // Allocate spinlock for split request completion.
832 KeInitializeSpinLock(&deviceExtension
->SplitRequestSpinLock
);
835 // This is the physical device.
838 deviceExtension
->PhysicalDevice
= deviceObject
;
841 // Initialize lock count to zero. The lock count is used to
842 // disable the ejection mechanism when media is mounted.
845 deviceExtension
->LockCount
= 0;
848 // Save system cdrom number
851 deviceExtension
->DeviceNumber
= *DeviceCount
;
854 // Copy port device object to device extension.
857 deviceExtension
->PortDeviceObject
= PortDeviceObject
;
860 // Set the alignment requirements for the device based on the
861 // host adapter requirements
864 if (PortDeviceObject
->AlignmentRequirement
> deviceObject
->AlignmentRequirement
) {
865 deviceObject
->AlignmentRequirement
= PortDeviceObject
->AlignmentRequirement
;
869 // Save address of port driver capabilities.
872 deviceExtension
->PortCapabilities
= PortCapabilities
;
878 deviceExtension
->SrbFlags
= 0;
879 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
882 // Allocate request sense buffer.
885 senseData
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
887 if (senseData
== NULL
) {
890 // The buffer cannot be allocated.
893 status
= STATUS_INSUFFICIENT_RESOURCES
;
894 goto CreateCdRomDeviceObjectExit
;
898 // Set the sense data pointer in the device extension.
901 deviceExtension
->SenseData
= senseData
;
904 // CDROMs are not partitionable so starting offset is 0.
907 deviceExtension
->StartingOffset
.LowPart
= 0;
908 deviceExtension
->StartingOffset
.HighPart
= 0;
911 // Path/TargetId/LUN describes a device location on the SCSI bus.
912 // This information comes from the LunInfo buffer.
915 deviceExtension
->PortNumber
= (UCHAR
)PortNumber
;
916 deviceExtension
->PathId
= LunInfo
->PathId
;
917 deviceExtension
->TargetId
= LunInfo
->TargetId
;
918 deviceExtension
->Lun
= LunInfo
->Lun
;
921 // Set timeout value in seconds.
924 timeOut
= ScsiClassQueryTimeOutRegistryValue(RegistryPath
);
926 deviceExtension
->TimeOutValue
= timeOut
;
928 deviceExtension
->TimeOutValue
= SCSI_CDROM_TIMEOUT
;
932 // Build the lookaside list for srb's for the physical disk. Should only
936 ScsiClassInitializeSrbLookasideList(deviceExtension
,
937 CDROM_SRB_LIST_SIZE
);
939 srbListInitialized
= TRUE
;
942 // Back pointer to device object.
945 deviceExtension
->DeviceObject
= deviceObject
;
948 // Allocate buffer for drive geometry.
951 deviceExtension
->DiskGeometry
=
952 ExAllocatePool(NonPagedPool
, sizeof(DISK_GEOMETRY_EX
));
954 if (deviceExtension
->DiskGeometry
== NULL
) {
956 status
= STATUS_INSUFFICIENT_RESOURCES
;
957 goto CreateCdRomDeviceObjectExit
;
961 // Set up media change support defaults.
964 cddata
= (PCDROM_DATA
)(deviceExtension
+ 1);
966 KeInitializeSpinLock(&cddata
->FormSpinLock
);
967 KeInitializeSpinLock(&cddata
->TimerIrpSpinLock
);
968 InitializeListHead(&cddata
->TimerIrpList
);
970 cddata
->MediaChangeCountDown
= MEDIA_CHANGE_DEFAULT_TIME
;
971 cddata
->MediaChangeSupported
= FALSE
;
972 cddata
->MediaChange
= FALSE
;
975 // Assume that there is initially no media in the device
976 // only notify upper layers if there is something there
979 deviceExtension
->MediaChangeNoMedia
= TRUE
;
980 cddata
->MediaChangeIrp
= NULL
;
982 cddata
->MediaChangeIrpTimeInUse
= 0;
983 cddata
->MediaChangeIrpLost
= FALSE
;
987 // Scan for Scsi controllers that require special processing.
990 ScanForSpecial(deviceObject
,
991 (PINQUIRYDATA
) LunInfo
->InquiryData
,
995 // Do READ CAPACITY. This SCSI command
996 // returns the last sector address on the device
997 // and the bytes per sector.
998 // These are used to calculate the drive capacity
1002 status
= ScsiClassReadDriveCapacity(deviceObject
);
1003 bps
= deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
;
1005 if (!NT_SUCCESS(status
) || !bps
) {
1008 "CreateCdRomDeviceObjects: Can't read capacity for device %s\n",
1012 // Set disk geometry to default values (per ISO 9660).
1016 deviceExtension
->SectorShift
= 11;
1017 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(0x7fffffff);
1021 // Insure that bytes per sector is a power of 2
1022 // This corrects a problem with the HP 4020i CDR where it
1023 // returns an incorrect number for bytes per sector.
1026 lastBit
= (ULONG
) -1;
1034 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= bps
;
1035 DebugPrint((2, "CreateCdRomDeviceObject: Calc'd bps = %x\n", bps
));
1038 // Check to see if this is some sort of changer device
1041 changerDevice
= FALSE
;
1044 // Search for devices that have special requirements for media
1048 if (deviceExtension
->Lun
> 0) {
1049 changerDevice
= TRUE
;
1052 if (!changerDevice
) {
1053 changerDevice
= IsThisASanyo(deviceObject
, deviceExtension
->PathId
,
1054 deviceExtension
->TargetId
);
1057 if (!changerDevice
) {
1059 changerDevice
= IsThisAnAtapiChanger(deviceObject
, &tmp
);
1062 if (!changerDevice
) {
1063 changerDevice
= IsThisAMultiLunDevice(deviceObject
, PortDeviceObject
);
1067 // If it is a changer device, increment the timeout to take platter-swapping
1068 // time into account
1072 deviceExtension
->TimeOutValue
+= SCSI_CHANGER_BONUS_TIMEOUT
;
1076 // Create the media change named event. If this succeeds then continue
1077 // initializing the media change support data items.
1080 CdRomCreateNamedEvent(deviceExtension
,*DeviceCount
);
1081 if (deviceExtension
->MediaChangeEvent
) {
1084 // If this is not a changer, get an IRP for the timer request
1085 // and initialize the timer.
1088 if (!changerDevice
) {
1091 // Not a changer device - continue with media change initialization.
1092 // Determine if the user actually wants media change events.
1095 if (CdRomCheckRegistryForMediaChangeValue(RegistryPath
, *DeviceCount
)) {
1096 PIO_STACK_LOCATION irpStack
;
1097 PSCSI_REQUEST_BLOCK srb
;
1101 // User wants it - preallocate IRP and SRB.
1104 irp
= IoAllocateIrp((CCHAR
)(deviceObject
->StackSize
+1),
1109 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
1110 buffer
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
1112 if (srb
&& buffer
) {
1116 // All resources have been allocated set up the IRP.
1119 IoSetNextIrpStackLocation(irp
);
1120 irpStack
= IoGetCurrentIrpStackLocation(irp
);
1121 irpStack
->DeviceObject
= deviceObject
;
1122 irpStack
= IoGetNextIrpStackLocation(irp
);
1123 cddata
->MediaChangeIrp
= irp
;
1124 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1127 // Initialize the SRB
1130 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
1133 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
* 2;
1134 srb
->QueueTag
= SP_UNTAGGED
;
1135 srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
1136 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1137 srb
->PathId
= deviceExtension
->PathId
;
1138 srb
->TargetId
= deviceExtension
->TargetId
;
1139 srb
->Lun
= deviceExtension
->Lun
;
1140 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1143 // Initialize and set up the sense information buffer
1146 RtlZeroMemory(buffer
, SENSE_BUFFER_SIZE
);
1147 srb
->SenseInfoBuffer
= buffer
;
1148 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1151 // Initialize the CDB
1154 cdb
= (PCDB
)&srb
->Cdb
[0];
1155 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_TEST_UNIT_READY
;
1156 cdb
->CDB6GENERIC
.LogicalUnitNumber
= deviceExtension
->Lun
;
1159 // It is ok to support media change events on this device.
1162 cddata
->MediaChangeSupported
= TRUE
;
1163 cddata
->MediaChange
= TRUE
;
1177 deviceExtension
->MediaChangeEvent
= NULL
;
1180 deviceExtension
->MediaChangeEvent
= NULL
;
1185 // Assume use of 6-byte mode sense/select for now.
1188 cddata
->XAFlags
|= XA_USE_6_BYTE
;
1191 // Build and issue mode sense with Read error recovery page. This will be used to change
1192 // block size in case of any raw reads (Mode 2, Form 2).
1195 length
= (sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH
);
1197 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
1200 cdb
= (PCDB
)srb
.Cdb
;
1203 // Set timeout value from device extension.
1206 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
1209 // Build the MODE SENSE CDB. The data returned will be kept in the device extension
1210 // and used to set block size.
1213 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
1214 cdb
->MODE_SENSE
.PageCode
= 0x1;
1215 cdb
->MODE_SENSE
.AllocationLength
= (UCHAR
)length
;
1217 buffer
= ExAllocatePool(NonPagedPoolCacheAligned
, (sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH10
));
1219 status
= STATUS_INSUFFICIENT_RESOURCES
;
1220 goto CreateCdRomDeviceObjectExit
;
1223 status
= ScsiClassSendSrbSynchronous(deviceObject
,
1228 if (!NT_SUCCESS(status
)) {
1231 // May be Atapi, try 10-byte.
1234 length
= (sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH10
);
1236 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
1239 // Build the MODE SENSE CDB.
1243 cdb
= (PCDB
)srb
.Cdb
;
1246 // Set timeout value from device extension.
1249 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
1251 cdb
->MODE_SENSE10
.OperationCode
= SCSIOP_MODE_SENSE10
;
1252 cdb
->MODE_SENSE10
.PageCode
= 0x1;
1254 cdb
->MODE_SENSE10
.AllocationLength
[0] = (UCHAR
)(length
>> 8);
1255 cdb
->MODE_SENSE10
.AllocationLength
[1] = (UCHAR
)(length
& 0xFF);
1257 status
= ScsiClassSendSrbSynchronous(deviceObject
,
1262 if (status
== STATUS_DATA_OVERRUN
) {
1265 // Build and issue the ReadCd command to ensure that this device supports it.
1268 RtlZeroMemory(cdb
, 12);
1270 cdb
->READ_CD
.OperationCode
= SCSIOP_READ_CD
;
1272 status
= ScsiClassSendSrbSynchronous(deviceObject
,
1279 // If the command wasn't rejected then support the READ_CD.
1282 if (NT_SUCCESS(status
) || (status
== STATUS_NO_MEDIA_IN_DEVICE
)) {
1285 // Using Read CD precludes issueing a mode select to
1286 // set the user data size. So, no buffer copy is
1290 cddata
->XAFlags
&= ~XA_USE_6_BYTE
;
1291 cddata
->XAFlags
= XA_USE_READ_CD
| XA_USE_10_BYTE
;
1294 RtlCopyMemory(&cddata
->u1
.Header
, buffer
, sizeof(ERROR_RECOVERY_DATA10
));
1295 cddata
->u1
.Header
.ModeDataLength
= 0;
1297 cddata
->XAFlags
&= ~XA_USE_6_BYTE
;
1298 cddata
->XAFlags
|= XA_USE_10_BYTE
;
1301 } else if (NT_SUCCESS(status
)) {
1303 RtlCopyMemory(&cddata
->u1
.Header
, buffer
, sizeof(ERROR_RECOVERY_DATA10
));
1304 cddata
->u1
.Header
.ModeDataLength
= 0;
1306 cddata
->XAFlags
&= ~XA_USE_6_BYTE
;
1307 cddata
->XAFlags
|= XA_USE_10_BYTE
;
1310 cddata
->XAFlags
|= XA_NOT_SUPPORTED
;
1313 RtlCopyMemory(&cddata
->u1
.Header
, buffer
, sizeof(ERROR_RECOVERY_DATA
));
1314 cddata
->u1
.Header
.ModeDataLength
= 0;
1320 // Start the timer now regardless of if Autorun is enabled.
1321 // The timer must run forever since IoStopTimer faults.
1324 IoInitializeTimer(deviceObject
, CdRomTickHandler
, NULL
);
1325 IoStartTimer(deviceObject
);
1327 return(STATUS_SUCCESS
);
1329 CreateCdRomDeviceObjectExit
:
1332 // Release the device since an error occured.
1335 ScsiClassClaimDevice(PortDeviceObject
,
1340 if (senseData
!= NULL
) {
1341 ExFreePool(senseData
);
1344 if (deviceExtension
->DiskGeometry
!= NULL
) {
1345 ExFreePool(deviceExtension
->DiskGeometry
);
1348 if (deviceObject
!= NULL
) {
1349 if (srbListInitialized
) {
1350 ExDeleteNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
);
1352 IoDeleteDevice(deviceObject
);
1358 } // end CreateCdRomDeviceObject()
1363 IN PDEVICE_OBJECT DeviceObject
,
1368 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1369 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1370 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
1371 PIO_STACK_LOCATION irpStack
;
1373 ULONG transferPages
;
1374 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
1375 ULONG maximumTransferLength
= deviceExtension
->PortCapabilities
->MaximumTransferLength
;
1377 PSCSI_REQUEST_BLOCK srb
= NULL
;
1379 PUCHAR senseBuffer
= NULL
;
1385 // Mark IRP with status pending.
1388 IoMarkIrpPending(Irp
);
1391 // If the flag is set in the device object, force a verify.
1394 if (DeviceObject
->Flags
& DO_VERIFY_VOLUME
) {
1395 DebugPrint((2, "ScsiCdRomStartIo: [%lx] Volume needs verified\n", Irp
));
1396 if (!(currentIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
)) {
1398 if (Irp
->Tail
.Overlay
.Thread
) {
1399 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
1402 Irp
->IoStatus
.Status
= STATUS_VERIFY_REQUIRED
;
1404 DebugPrint((2, "ScsiCdRomStartIo: [%lx] Calling UpdateCapcity - "
1405 "ioctl event = %lx\n",
1407 nextIrpStack
->Parameters
.Others
.Argument1
1411 // our device control dispatch routine stores an event in the next
1412 // stack location to signal when startio has completed. We need to
1413 // pass this in so that the update capacity completion routine can
1414 // set it rather than completing the Irp.
1417 status
= CdRomUpdateCapacity(deviceExtension
,
1419 nextIrpStack
->Parameters
.Others
.Argument1
1422 DebugPrint((2, "ScsiCdRomStartIo: [%lx] UpdateCapacity returned %lx\n", Irp
, status
));
1423 ASSERT(status
== STATUS_PENDING
);
1428 cdData
= (PCDROM_DATA
)(deviceExtension
+ 1);
1429 use6Byte
= cdData
->XAFlags
& XA_USE_6_BYTE
;
1431 if (currentIrpStack
->MajorFunction
== IRP_MJ_READ
) {
1434 // Add partition byte offset to make starting byte relative to
1435 // beginning of disk. In addition, add in skew for DM Driver, if any.
1438 currentIrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+= (deviceExtension
->StartingOffset
.QuadPart
);
1441 // Calculate number of pages in this transfer.
1444 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp
->MdlAddress
),
1445 currentIrpStack
->Parameters
.Read
.Length
);
1448 // Check if request length is greater than the maximum number of
1449 // bytes that the hardware can transfer.
1452 if (cdData
->RawAccess
) {
1454 ASSERT(!(cdData
->XAFlags
& XA_USE_READ_CD
));
1457 // Fire off a mode select to switch back to cooked sectors.
1460 irp2
= IoAllocateIrp((CCHAR
)(deviceExtension
->DeviceObject
->StackSize
+1),
1464 Irp
->IoStatus
.Information
= 0;
1465 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1466 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1467 IoStartNextPacket(DeviceObject
, FALSE
);
1471 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
1473 Irp
->IoStatus
.Information
= 0;
1474 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1475 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1477 IoStartNextPacket(DeviceObject
, FALSE
);
1481 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
1483 cdb
= (PCDB
)srb
->Cdb
;
1486 // Allocate sense buffer.
1489 senseBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
1492 Irp
->IoStatus
.Information
= 0;
1493 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1494 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1497 IoStartNextPacket(DeviceObject
, FALSE
);
1505 IoSetNextIrpStackLocation(irp2
);
1506 irp2
->IoStatus
.Status
= STATUS_SUCCESS
;
1507 irp2
->IoStatus
.Information
= 0;
1509 irp2
->UserBuffer
= NULL
;
1512 // Save the device object and irp in a private stack location.
1515 irpStack
= IoGetCurrentIrpStackLocation(irp2
);
1516 irpStack
->DeviceObject
= deviceExtension
->DeviceObject
;
1517 irpStack
->Parameters
.Others
.Argument2
= (PVOID
) Irp
;
1520 // The retry count will be in the real Irp, as the retry logic will
1521 // recreate our private irp.
1524 if (!(nextIrpStack
->Parameters
.Others
.Argument1
)) {
1527 // Only jam this in if it doesn't exist. The completion routines can
1528 // call StartIo directly in the case of retries and resetting it will
1529 // cause infinite loops.
1532 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
1536 // Construct the IRP stack for the lower level driver.
1539 irpStack
= IoGetNextIrpStackLocation(irp2
);
1540 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
1541 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
1542 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1544 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1545 srb
->PathId
= deviceExtension
->PathId
;
1546 srb
->TargetId
= deviceExtension
->TargetId
;
1547 srb
->Lun
= deviceExtension
->Lun
;
1548 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1549 srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
1550 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
1552 srb
->OriginalRequest
= irp2
;
1553 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1554 srb
->SenseInfoBuffer
= senseBuffer
;
1556 transferByteCount
= (use6Byte
) ? sizeof(ERROR_RECOVERY_DATA
) : sizeof(ERROR_RECOVERY_DATA10
);
1557 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, transferByteCount
);
1559 Irp
->IoStatus
.Information
= 0;
1560 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1561 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1562 ExFreePool(senseBuffer
);
1565 IoStartNextPacket(DeviceObject
, FALSE
);
1570 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
1576 if (!irp2
->MdlAddress
) {
1577 Irp
->IoStatus
.Information
= 0;
1578 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1579 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1580 ExFreePool(senseBuffer
);
1582 ExFreePool(dataBuffer
);
1584 IoStartNextPacket(DeviceObject
, FALSE
);
1592 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
1594 srb
->DataBuffer
= dataBuffer
;
1597 // Set the new block size in the descriptor.
1600 cdData
->u1
.BlockDescriptor
.BlockLength
[0] = (UCHAR
)(COOKED_SECTOR_SIZE
>> 16) & 0xFF;
1601 cdData
->u1
.BlockDescriptor
.BlockLength
[1] = (UCHAR
)(COOKED_SECTOR_SIZE
>> 8) & 0xFF;
1602 cdData
->u1
.BlockDescriptor
.BlockLength
[2] = (UCHAR
)(COOKED_SECTOR_SIZE
& 0xFF);
1605 // Move error page into dataBuffer.
1608 RtlCopyMemory(srb
->DataBuffer
, &cdData
->u1
.Header
, transferByteCount
);
1611 // Build and send a mode select to switch into raw mode.
1614 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
1615 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_OUT
);
1616 srb
->DataTransferLength
= transferByteCount
;
1617 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
* 2;
1621 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
1622 cdb
->MODE_SELECT
.PFBit
= 1;
1623 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)transferByteCount
;
1626 srb
->CdbLength
= 10;
1627 cdb
->MODE_SELECT10
.OperationCode
= SCSIOP_MODE_SELECT10
;
1628 cdb
->MODE_SELECT10
.PFBit
= 1;
1629 cdb
->MODE_SELECT10
.ParameterListLength
[0] = (UCHAR
)(transferByteCount
>> 8);
1630 cdb
->MODE_SELECT10
.ParameterListLength
[1] = (UCHAR
)(transferByteCount
& 0xFF);
1634 // Update completion routine.
1637 IoSetCompletionRoutine(irp2
,
1638 CdRomSwitchModeCompletion
,
1644 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
1648 if ((currentIrpStack
->Parameters
.Read
.Length
> maximumTransferLength
) ||
1650 deviceExtension
->PortCapabilities
->MaximumPhysicalPages
)) {
1653 // Request needs to be split. Completion of each portion of the
1654 // request will fire off the next portion. The final request will
1655 // signal Io to send a new request.
1659 deviceExtension
->PortCapabilities
->MaximumPhysicalPages
- 1;
1661 if(maximumTransferLength
> transferPages
<< PAGE_SHIFT
) {
1662 maximumTransferLength
= transferPages
<< PAGE_SHIFT
;
1666 // Check that the maximum transfer size is not zero
1669 if(maximumTransferLength
== 0) {
1670 maximumTransferLength
= PAGE_SIZE
;
1673 ScsiClassSplitRequest(DeviceObject
, Irp
, maximumTransferLength
);
1679 // Build SRB and CDB for this IRP.
1682 ScsiClassBuildRequest(DeviceObject
, Irp
);
1687 } else if (currentIrpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
) {
1690 // Allocate an irp, srb and associated structures.
1693 irp2
= IoAllocateIrp((CCHAR
)(deviceExtension
->DeviceObject
->StackSize
+1),
1697 Irp
->IoStatus
.Information
= 0;
1698 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1699 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1700 IoStartNextPacket(DeviceObject
, FALSE
);
1701 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp
, Irp
->IoStatus
.Status
, __LINE__
));
1705 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
1707 Irp
->IoStatus
.Information
= 0;
1708 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1709 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1711 IoStartNextPacket(DeviceObject
, FALSE
);
1712 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp
, Irp
->IoStatus
.Status
, __LINE__
));
1716 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
1718 cdb
= (PCDB
)srb
->Cdb
;
1721 // Allocate sense buffer.
1724 senseBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
1727 Irp
->IoStatus
.Information
= 0;
1728 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1729 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1732 IoStartNextPacket(DeviceObject
, FALSE
);
1733 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp
, Irp
->IoStatus
.Status
, __LINE__
));
1741 IoSetNextIrpStackLocation(irp2
);
1742 irp2
->IoStatus
.Status
= STATUS_SUCCESS
;
1743 irp2
->IoStatus
.Information
= 0;
1745 irp2
->UserBuffer
= NULL
;
1748 // Save the device object and irp in a private stack location.
1751 irpStack
= IoGetCurrentIrpStackLocation(irp2
);
1752 irpStack
->DeviceObject
= deviceExtension
->DeviceObject
;
1753 irpStack
->Parameters
.Others
.Argument2
= (PVOID
) Irp
;
1756 // The retry count will be in the real Irp, as the retry logic will
1757 // recreate our private irp.
1760 if (!(nextIrpStack
->Parameters
.Others
.Argument1
)) {
1763 // Only jam this in if it doesn't exist. The completion routines can
1764 // call StartIo directly in the case of retries and resetting it will
1765 // cause infinite loops.
1768 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
1772 // Construct the IRP stack for the lower level driver.
1775 irpStack
= IoGetNextIrpStackLocation(irp2
);
1776 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
1777 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
1778 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1780 IoSetCompletionRoutine(irp2
,
1781 CdRomDeviceControlCompletion
,
1787 // Setup those fields that are generic to all requests.
1790 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1791 srb
->PathId
= deviceExtension
->PathId
;
1792 srb
->TargetId
= deviceExtension
->TargetId
;
1793 srb
->Lun
= deviceExtension
->Lun
;
1794 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1795 srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
1796 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
1798 srb
->OriginalRequest
= irp2
;
1799 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1800 srb
->SenseInfoBuffer
= senseBuffer
;
1802 switch (currentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
) {
1804 case IOCTL_CDROM_RAW_READ
: {
1807 // Determine whether the drive is currently in raw or cooked mode,
1808 // and which command to use to read the data.
1811 if (!(cdData
->XAFlags
& XA_USE_READ_CD
)) {
1813 PRAW_READ_INFO rawReadInfo
=
1814 (PRAW_READ_INFO
)currentIrpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
1815 ULONG maximumTransferLength
;
1816 ULONG transferPages
;
1818 if (cdData
->RawAccess
) {
1820 ULONG startingSector
;
1823 // Free the recently allocated irp, as we don't need it.
1828 cdb
= (PCDB
)srb
->Cdb
;
1829 RtlZeroMemory(cdb
, 12);
1832 // Calculate starting offset.
1835 startingSector
= (ULONG
)(rawReadInfo
->DiskOffset
.QuadPart
>> deviceExtension
->SectorShift
);
1836 transferByteCount
= rawReadInfo
->SectorCount
* RAW_SECTOR_SIZE
;
1837 maximumTransferLength
= deviceExtension
->PortCapabilities
->MaximumTransferLength
;
1838 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp
->MdlAddress
),
1842 // Determine if request is within limits imposed by miniport.
1845 if (transferByteCount
> maximumTransferLength
||
1846 transferPages
> deviceExtension
->PortCapabilities
->MaximumPhysicalPages
) {
1849 // The claim is that this won't happen, and is backed up by
1850 // ActiveMovie usage, which does unbuffered XA reads of 0x18000, yet
1851 // we get only 4 sector requests.
1855 Irp
->IoStatus
.Information
= 0;
1856 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
1857 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1858 ExFreePool(senseBuffer
);
1860 IoStartNextPacket(DeviceObject
, FALSE
);
1865 srb
->OriginalRequest
= Irp
;
1866 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
1867 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
1868 srb
->DataTransferLength
= transferByteCount
;
1869 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
1870 srb
->CdbLength
= 10;
1871 srb
->DataBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
1873 if (rawReadInfo
->TrackMode
== CDDA
) {
1874 if (cdData
->XAFlags
& PLEXTOR_CDDA
) {
1876 srb
->CdbLength
= 12;
1878 cdb
->PLXTR_READ_CDDA
.LogicalUnitNumber
= deviceExtension
->Lun
;
1879 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
1880 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
1881 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
1882 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
1884 cdb
->PLXTR_READ_CDDA
.TransferBlockByte3
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
1885 cdb
->PLXTR_READ_CDDA
.TransferBlockByte2
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
1886 cdb
->PLXTR_READ_CDDA
.TransferBlockByte1
= 0;
1887 cdb
->PLXTR_READ_CDDA
.TransferBlockByte0
= 0;
1889 cdb
->PLXTR_READ_CDDA
.SubCode
= 0;
1890 cdb
->PLXTR_READ_CDDA
.OperationCode
= 0xD8;
1892 } else if (cdData
->XAFlags
& NEC_CDDA
) {
1894 cdb
->NEC_READ_CDDA
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
1895 cdb
->NEC_READ_CDDA
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
1896 cdb
->NEC_READ_CDDA
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
1897 cdb
->NEC_READ_CDDA
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
1899 cdb
->NEC_READ_CDDA
.TransferBlockByte1
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
1900 cdb
->NEC_READ_CDDA
.TransferBlockByte0
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
1902 cdb
->NEC_READ_CDDA
.OperationCode
= 0xD4;
1906 cdb
->CDB10
.LogicalUnitNumber
= deviceExtension
->Lun
;
1908 cdb
->CDB10
.TransferBlocksMsb
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
1909 cdb
->CDB10
.TransferBlocksLsb
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
1911 cdb
->CDB10
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
1912 cdb
->CDB10
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
1913 cdb
->CDB10
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
1914 cdb
->CDB10
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
1916 cdb
->CDB10
.OperationCode
= SCSIOP_READ
;
1919 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
1921 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
1922 nextIrpStack
->Parameters
.Scsi
.Srb
= srb
;
1924 if (!(nextIrpStack
->Parameters
.Others
.Argument1
)) {
1927 // Only jam this in if it doesn't exist. The completion routines can
1928 // call StartIo directly in the case of retries and resetting it will
1929 // cause infinite loops.
1932 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
1936 // Set up IoCompletion routine address.
1939 IoSetCompletionRoutine(Irp
,
1946 IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
1951 transferByteCount
= (use6Byte
) ? sizeof(ERROR_RECOVERY_DATA
) : sizeof(ERROR_RECOVERY_DATA10
);
1952 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, transferByteCount
);
1954 Irp
->IoStatus
.Information
= 0;
1955 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1956 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1957 ExFreePool(senseBuffer
);
1960 IoStartNextPacket(DeviceObject
, FALSE
);
1965 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
1971 if (!irp2
->MdlAddress
) {
1972 Irp
->IoStatus
.Information
= 0;
1973 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1974 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1975 ExFreePool(senseBuffer
);
1977 ExFreePool(dataBuffer
);
1979 IoStartNextPacket(DeviceObject
, FALSE
);
1987 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
1989 srb
->DataBuffer
= dataBuffer
;
1992 // Set the new block size in the descriptor.
1995 cdData
->u1
.BlockDescriptor
.BlockLength
[0] = (UCHAR
)(RAW_SECTOR_SIZE
>> 16) & 0xFF;
1996 cdData
->u1
.BlockDescriptor
.BlockLength
[1] = (UCHAR
)(RAW_SECTOR_SIZE
>> 8) & 0xFF;
1997 cdData
->u1
.BlockDescriptor
.BlockLength
[2] = (UCHAR
)(RAW_SECTOR_SIZE
& 0xFF);
2001 // TODO: Set density code, based on operation
2004 cdData
->u1
.BlockDescriptor
.DensityCode
= 0;
2008 // Move error page into dataBuffer.
2011 RtlCopyMemory(srb
->DataBuffer
, &cdData
->u1
.Header
, transferByteCount
);
2015 // Build and send a mode select to switch into raw mode.
2018 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2019 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_OUT
);
2020 srb
->DataTransferLength
= transferByteCount
;
2021 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
* 2;
2025 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
2026 cdb
->MODE_SELECT
.PFBit
= 1;
2027 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)transferByteCount
;
2030 srb
->CdbLength
= 10;
2031 cdb
->MODE_SELECT10
.OperationCode
= SCSIOP_MODE_SELECT10
;
2032 cdb
->MODE_SELECT10
.PFBit
= 1;
2033 cdb
->MODE_SELECT10
.ParameterListLength
[0] = (UCHAR
)(transferByteCount
>> 8);
2034 cdb
->MODE_SELECT10
.ParameterListLength
[1] = (UCHAR
)(transferByteCount
& 0xFF);
2038 // Update completion routine.
2041 IoSetCompletionRoutine(irp2
,
2042 CdRomSwitchModeCompletion
,
2052 PRAW_READ_INFO rawReadInfo
=
2053 (PRAW_READ_INFO
)currentIrpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
2054 ULONG startingSector
;
2057 // Free the recently allocated irp, as we don't need it.
2062 cdb
= (PCDB
)srb
->Cdb
;
2063 RtlZeroMemory(cdb
, 12);
2067 // Calculate starting offset.
2070 startingSector
= (ULONG
)(rawReadInfo
->DiskOffset
.QuadPart
>> deviceExtension
->SectorShift
);
2071 transferByteCount
= rawReadInfo
->SectorCount
* RAW_SECTOR_SIZE
;
2074 srb
->OriginalRequest
= Irp
;
2075 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2076 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
2077 srb
->DataTransferLength
= transferByteCount
;
2078 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2079 srb
->DataBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
2080 srb
->CdbLength
= 12;
2081 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
2084 // Fill in CDB fields.
2087 cdb
= (PCDB
)srb
->Cdb
;
2090 cdb
->READ_CD
.TransferBlocks
[2] = (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
2091 cdb
->READ_CD
.TransferBlocks
[1] = (UCHAR
) (rawReadInfo
->SectorCount
>> 8 );
2092 cdb
->READ_CD
.TransferBlocks
[0] = (UCHAR
) (rawReadInfo
->SectorCount
>> 16);
2095 cdb
->READ_CD
.StartingLBA
[3] = (UCHAR
) (startingSector
& 0xFF);
2096 cdb
->READ_CD
.StartingLBA
[2] = (UCHAR
) ((startingSector
>> 8));
2097 cdb
->READ_CD
.StartingLBA
[1] = (UCHAR
) ((startingSector
>> 16));
2098 cdb
->READ_CD
.StartingLBA
[0] = (UCHAR
) ((startingSector
>> 24));
2101 // Setup cdb depending upon the sector type we want.
2104 switch (rawReadInfo
->TrackMode
) {
2107 cdb
->READ_CD
.ExpectedSectorType
= CD_DA_SECTOR
;
2108 cdb
->READ_CD
.IncludeUserData
= 1;
2109 cdb
->READ_CD
.HeaderCode
= 3;
2110 cdb
->READ_CD
.IncludeSyncData
= 1;
2115 cdb
->READ_CD
.ExpectedSectorType
= YELLOW_MODE2_SECTOR
;
2116 cdb
->READ_CD
.IncludeUserData
= 1;
2117 cdb
->READ_CD
.HeaderCode
= 1;
2118 cdb
->READ_CD
.IncludeSyncData
= 1;
2123 cdb
->READ_CD
.ExpectedSectorType
= FORM2_MODE2_SECTOR
;
2124 cdb
->READ_CD
.IncludeUserData
= 1;
2125 cdb
->READ_CD
.HeaderCode
= 3;
2126 cdb
->READ_CD
.IncludeSyncData
= 1;
2130 Irp
->IoStatus
.Information
= 0;
2131 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
2132 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2133 ExFreePool(senseBuffer
);
2136 IoStartNextPacket(DeviceObject
, FALSE
);
2137 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp
, Irp
->IoStatus
.Status
, __LINE__
));
2141 cdb
->READ_CD
.OperationCode
= SCSIOP_READ_CD
;
2143 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
2144 nextIrpStack
->Parameters
.Scsi
.Srb
= srb
;
2146 if (!(nextIrpStack
->Parameters
.Others
.Argument1
)) {
2149 // Only jam this in if it doesn't exist. The completion routines can
2150 // call StartIo directly in the case of retries and resetting it will
2151 // cause infinite loops.
2154 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
2158 // Set up IoCompletion routine address.
2161 IoSetCompletionRoutine(Irp
,
2168 IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
2173 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2177 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
: {
2180 // Issue ReadCapacity to update device extension
2181 // with information for current media.
2185 "CdRomStartIo: Get drive capacity\n"));
2188 // setup remaining srb and cdb parameters.
2191 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2192 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
2193 srb
->DataTransferLength
= sizeof(READ_CAPACITY_DATA
);
2194 srb
->CdbLength
= 10;
2195 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2197 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, sizeof(READ_CAPACITY_DATA
));
2199 Irp
->IoStatus
.Information
= 0;
2200 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2201 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2202 ExFreePool(senseBuffer
);
2205 IoStartNextPacket(DeviceObject
, FALSE
);
2206 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp
, Irp
->IoStatus
.Status
, __LINE__
));
2211 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2212 sizeof(READ_CAPACITY_DATA
),
2217 if (!irp2
->MdlAddress
) {
2218 Irp
->IoStatus
.Information
= 0;
2219 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2220 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2221 ExFreePool(senseBuffer
);
2223 ExFreePool(dataBuffer
);
2225 IoStartNextPacket(DeviceObject
, FALSE
);
2226 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp
, Irp
->IoStatus
.Status
, __LINE__
));
2234 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2236 srb
->DataBuffer
= dataBuffer
;
2237 cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
2239 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2243 case IOCTL_CDROM_CHECK_VERIFY
: {
2246 // Since a test unit ready is about to be performed, reset the timer
2247 // value to decrease the opportunities for it to race with this code.
2250 cdData
->MediaChangeCountDown
= MEDIA_CHANGE_DEFAULT_TIME
;
2253 // Set up the SRB/CDB
2257 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_TEST_UNIT_READY
;
2258 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
* 2;
2259 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2260 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_NO_DATA_TRANSFER
);
2262 DebugPrint((2, "ScsiCdRomStartIo: [%lx] Sending CHECK_VERIFY irp %lx\n", Irp
, irp2
));
2263 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2267 case IOCTL_CDROM_GET_LAST_SESSION
:
2270 // Set format to return first and last session numbers.
2273 cdb
->READ_TOC
.Format
= GET_LAST_SESSION
;
2276 // Fall through to READ TOC code.
2279 case IOCTL_CDROM_READ_TOC
: {
2282 if (currentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_READ_TOC
) {
2285 // Use MSF addressing if not request for session information.
2288 cdb
->READ_TOC
.Msf
= CDB_USE_MSF
;
2292 // Set size of TOC structure.
2296 currentIrpStack
->Parameters
.Read
.Length
>
2297 sizeof(CDROM_TOC
) ? sizeof(CDROM_TOC
):
2298 currentIrpStack
->Parameters
.Read
.Length
;
2300 cdb
->READ_TOC
.AllocationLength
[0] = (UCHAR
) (transferByteCount
>> 8);
2301 cdb
->READ_TOC
.AllocationLength
[1] = (UCHAR
) (transferByteCount
& 0xFF);
2303 cdb
->READ_TOC
.Control
= 0;
2306 // Start at beginning of disc.
2309 cdb
->READ_TOC
.StartingTrack
= 0;
2312 // setup remaining srb and cdb parameters.
2315 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2316 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
2317 srb
->DataTransferLength
= transferByteCount
;
2318 srb
->CdbLength
= 10;
2319 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2321 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, transferByteCount
);
2323 Irp
->IoStatus
.Information
= 0;
2324 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2325 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2326 ExFreePool(senseBuffer
);
2329 IoStartNextPacket(DeviceObject
, FALSE
);
2334 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2340 if (!irp2
->MdlAddress
) {
2341 Irp
->IoStatus
.Information
= 0;
2342 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2343 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2344 ExFreePool(senseBuffer
);
2346 ExFreePool(dataBuffer
);
2348 IoStartNextPacket(DeviceObject
, FALSE
);
2356 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2358 srb
->DataBuffer
= dataBuffer
;
2359 cdb
->READ_TOC
.OperationCode
= SCSIOP_READ_TOC
;
2361 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2366 case IOCTL_CDROM_PLAY_AUDIO_MSF
: {
2368 PCDROM_PLAY_AUDIO_MSF inputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
2371 // Set up the SRB/CDB
2374 srb
->CdbLength
= 10;
2375 cdb
->PLAY_AUDIO_MSF
.OperationCode
= SCSIOP_PLAY_AUDIO_MSF
;
2377 cdb
->PLAY_AUDIO_MSF
.StartingM
= inputBuffer
->StartingM
;
2378 cdb
->PLAY_AUDIO_MSF
.StartingS
= inputBuffer
->StartingS
;
2379 cdb
->PLAY_AUDIO_MSF
.StartingF
= inputBuffer
->StartingF
;
2381 cdb
->PLAY_AUDIO_MSF
.EndingM
= inputBuffer
->EndingM
;
2382 cdb
->PLAY_AUDIO_MSF
.EndingS
= inputBuffer
->EndingS
;
2383 cdb
->PLAY_AUDIO_MSF
.EndingF
= inputBuffer
->EndingF
;
2385 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2386 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2387 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_NO_DATA_TRANSFER
);
2389 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2394 case IOCTL_CDROM_READ_Q_CHANNEL
: {
2396 PCDROM_SUB_Q_DATA_FORMAT inputBuffer
=
2397 Irp
->AssociatedIrp
.SystemBuffer
;
2400 // Allocate buffer for subq channel information.
2403 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
2404 sizeof(SUB_Q_CHANNEL_DATA
));
2407 Irp
->IoStatus
.Information
= 0;
2408 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2409 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2410 ExFreePool(senseBuffer
);
2413 IoStartNextPacket(DeviceObject
, FALSE
);
2418 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2424 if (!irp2
->MdlAddress
) {
2425 Irp
->IoStatus
.Information
= 0;
2426 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2427 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2428 ExFreePool(senseBuffer
);
2430 ExFreePool(dataBuffer
);
2432 IoStartNextPacket(DeviceObject
, FALSE
);
2440 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2442 srb
->DataBuffer
= dataBuffer
;
2445 // Always logical unit 0, but only use MSF addressing
2446 // for IOCTL_CDROM_CURRENT_POSITION
2449 if (inputBuffer
->Format
==IOCTL_CDROM_CURRENT_POSITION
)
2450 cdb
->SUBCHANNEL
.Msf
= CDB_USE_MSF
;
2453 // Return subchannel data
2456 cdb
->SUBCHANNEL
.SubQ
= CDB_SUBCHANNEL_BLOCK
;
2459 // Specify format of informatin to return
2462 cdb
->SUBCHANNEL
.Format
= inputBuffer
->Format
;
2465 // Specify which track to access (only used by Track ISRC reads)
2468 if (inputBuffer
->Format
==IOCTL_CDROM_TRACK_ISRC
) {
2469 cdb
->SUBCHANNEL
.TrackNumber
= inputBuffer
->Track
;
2473 // Set size of channel data -- however, this is dependent on
2474 // what information we are requesting (which Format)
2477 switch( inputBuffer
->Format
) {
2479 case IOCTL_CDROM_CURRENT_POSITION
:
2480 transferByteCount
= sizeof(SUB_Q_CURRENT_POSITION
);
2483 case IOCTL_CDROM_MEDIA_CATALOG
:
2484 transferByteCount
= sizeof(SUB_Q_MEDIA_CATALOG_NUMBER
);
2487 case IOCTL_CDROM_TRACK_ISRC
:
2488 transferByteCount
= sizeof(SUB_Q_TRACK_ISRC
);
2492 cdb
->SUBCHANNEL
.AllocationLength
[0] = (UCHAR
) (transferByteCount
>> 8);
2493 cdb
->SUBCHANNEL
.AllocationLength
[1] = (UCHAR
) (transferByteCount
& 0xFF);
2494 cdb
->SUBCHANNEL
.OperationCode
= SCSIOP_READ_SUB_CHANNEL
;
2495 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2496 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
2497 srb
->DataTransferLength
= transferByteCount
;
2498 srb
->CdbLength
= 10;
2499 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2501 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2506 case IOCTL_CDROM_PAUSE_AUDIO
: {
2508 cdb
->PAUSE_RESUME
.OperationCode
= SCSIOP_PAUSE_RESUME
;
2509 cdb
->PAUSE_RESUME
.Action
= CDB_AUDIO_PAUSE
;
2511 srb
->CdbLength
= 10;
2512 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2513 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2514 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_NO_DATA_TRANSFER
);
2516 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2520 case IOCTL_CDROM_RESUME_AUDIO
: {
2522 cdb
->PAUSE_RESUME
.OperationCode
= SCSIOP_PAUSE_RESUME
;
2523 cdb
->PAUSE_RESUME
.Action
= CDB_AUDIO_RESUME
;
2525 srb
->CdbLength
= 10;
2526 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2527 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2528 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_NO_DATA_TRANSFER
);
2530 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2534 case IOCTL_CDROM_SEEK_AUDIO_MSF
: {
2536 PCDROM_SEEK_AUDIO_MSF inputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
2537 ULONG logicalBlockAddress
;
2539 logicalBlockAddress
= MSF_TO_LBA(inputBuffer
->M
, inputBuffer
->S
, inputBuffer
->F
);
2541 cdb
->SEEK
.OperationCode
= SCSIOP_SEEK
;
2542 cdb
->SEEK
.LogicalBlockAddress
[0] = ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte3
;
2543 cdb
->SEEK
.LogicalBlockAddress
[1] = ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte2
;
2544 cdb
->SEEK
.LogicalBlockAddress
[2] = ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte1
;
2545 cdb
->SEEK
.LogicalBlockAddress
[3] = ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte0
;
2547 srb
->CdbLength
= 10;
2548 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2549 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2550 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_NO_DATA_TRANSFER
);
2552 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2557 case IOCTL_CDROM_STOP_AUDIO
: {
2559 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
2560 cdb
->START_STOP
.Immediate
= 1;
2561 cdb
->START_STOP
.Start
= 0;
2562 cdb
->START_STOP
.LoadEject
= 0;
2565 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2567 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2568 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_NO_DATA_TRANSFER
);
2570 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2574 case IOCTL_CDROM_GET_CONTROL
: {
2576 // Allocate buffer for volume control information.
2579 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
2583 Irp
->IoStatus
.Information
= 0;
2584 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2585 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2586 ExFreePool(senseBuffer
);
2589 IoStartNextPacket(DeviceObject
, FALSE
);
2594 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2600 if (!irp2
->MdlAddress
) {
2601 Irp
->IoStatus
.Information
= 0;
2602 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2603 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2604 ExFreePool(senseBuffer
);
2606 ExFreePool(dataBuffer
);
2608 IoStartNextPacket(DeviceObject
, FALSE
);
2616 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2617 srb
->DataBuffer
= dataBuffer
;
2619 RtlZeroMemory(dataBuffer
, MODE_DATA_SIZE
);
2622 // Setup for either 6 or 10 byte CDBs.
2627 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
2628 cdb
->MODE_SENSE
.PageCode
= CDROM_AUDIO_CONTROL_PAGE
;
2629 cdb
->MODE_SENSE
.AllocationLength
= MODE_DATA_SIZE
;
2632 // Disable block descriptors.
2635 cdb
->MODE_SENSE
.Dbd
= TRUE
;
2640 cdb
->MODE_SENSE10
.OperationCode
= SCSIOP_MODE_SENSE10
;
2641 cdb
->MODE_SENSE10
.PageCode
= CDROM_AUDIO_CONTROL_PAGE
;
2642 cdb
->MODE_SENSE10
.AllocationLength
[0] = (UCHAR
)(MODE_DATA_SIZE
>> 8);
2643 cdb
->MODE_SENSE10
.AllocationLength
[1] = (UCHAR
)(MODE_DATA_SIZE
& 0xFF);
2646 // Disable block descriptors.
2649 cdb
->MODE_SENSE10
.Dbd
= TRUE
;
2651 srb
->CdbLength
= 10;
2654 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2655 srb
->DataTransferLength
= MODE_DATA_SIZE
;
2656 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2657 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
2659 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2664 case IOCTL_CDROM_GET_VOLUME
:
2665 case IOCTL_CDROM_SET_VOLUME
: {
2667 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
2671 Irp
->IoStatus
.Information
= 0;
2672 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2673 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2674 ExFreePool(senseBuffer
);
2677 IoStartNextPacket(DeviceObject
, FALSE
);
2681 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2687 if (!irp2
->MdlAddress
) {
2688 Irp
->IoStatus
.Information
= 0;
2689 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2690 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2691 ExFreePool(senseBuffer
);
2693 ExFreePool(dataBuffer
);
2695 IoStartNextPacket(DeviceObject
, FALSE
);
2703 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2704 srb
->DataBuffer
= dataBuffer
;
2706 RtlZeroMemory(dataBuffer
, MODE_DATA_SIZE
);
2710 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
2711 cdb
->MODE_SENSE
.PageCode
= CDROM_AUDIO_CONTROL_PAGE
;
2712 cdb
->MODE_SENSE
.AllocationLength
= MODE_DATA_SIZE
;
2718 cdb
->MODE_SENSE10
.OperationCode
= SCSIOP_MODE_SENSE10
;
2719 cdb
->MODE_SENSE10
.PageCode
= CDROM_AUDIO_CONTROL_PAGE
;
2720 cdb
->MODE_SENSE10
.AllocationLength
[0] = (UCHAR
)(MODE_DATA_SIZE
>> 8);
2721 cdb
->MODE_SENSE10
.AllocationLength
[1] = (UCHAR
)(MODE_DATA_SIZE
& 0xFF);
2723 srb
->CdbLength
= 10;
2726 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2727 srb
->DataTransferLength
= MODE_DATA_SIZE
;
2728 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2729 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
2731 if (currentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_SET_VOLUME
) {
2734 // Setup a different completion routine as the mode sense data is needed in order
2735 // to send the mode select.
2738 IoSetCompletionRoutine(irp2
,
2739 CdRomSetVolumeIntermediateCompletion
,
2747 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2755 // Just complete the request - CdRomClassIoctlCompletion will take
2756 // care of it for us
2759 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2766 // If a read or an unhandled IRP_MJ_XX, end up here. The unhandled IRP_MJ's
2767 // are expected and composed of AutoRun Irps, at present.
2770 IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
2777 ScsiCdRomReadVerification(
2778 IN PDEVICE_OBJECT DeviceObject
,
2784 Routine Description:
2786 This is the entry called by the I/O system for read requests.
2787 It builds the SRB and sends it to the port driver.
2791 DeviceObject - the system object for the device.
2801 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2802 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
2803 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
2804 LARGE_INTEGER startingOffset
= currentIrpStack
->Parameters
.Read
.ByteOffset
;
2807 // If the cd is playing music then reject this request.
2810 if (PLAY_ACTIVE(deviceExtension
)) {
2811 Irp
->IoStatus
.Status
= STATUS_DEVICE_BUSY
;
2812 return STATUS_DEVICE_BUSY
;
2816 // Verify parameters of this request.
2817 // Check that ending sector is on disc and
2818 // that number of bytes to transfer is a multiple of
2822 startingOffset
.QuadPart
= currentIrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+
2825 if (!deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
) {
2826 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= 2048;
2829 if ((startingOffset
.QuadPart
> deviceExtension
->PartitionLength
.QuadPart
) ||
2830 (transferByteCount
& (deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
- 1))) {
2832 DebugPrint((1,"ScsiCdRomRead: Invalid I/O parameters\n"));
2833 DebugPrint((1, "\toffset %x:%x, Length %x:%x\n",
2834 startingOffset
.u
.HighPart
,
2835 startingOffset
.u
.LowPart
,
2836 deviceExtension
->PartitionLength
.u
.HighPart
,
2837 deviceExtension
->PartitionLength
.u
.LowPart
));
2838 DebugPrint((1, "\tbps %x\n", deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
));
2841 // Fail request with status of invalid parameters.
2844 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
2846 return STATUS_INVALID_PARAMETER
;
2850 return STATUS_SUCCESS
;
2852 } // end ScsiCdRomReadVerification()
2857 CdRomDeviceControlCompletion(
2858 IN PDEVICE_OBJECT DeviceObject
,
2863 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2864 PDEVICE_EXTENSION physicalExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
2865 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
2866 PCDROM_DATA cdData
= (PCDROM_DATA
)(deviceExtension
+ 1);
2867 BOOLEAN use6Byte
= cdData
->XAFlags
& XA_USE_6_BYTE
;
2868 PIO_STACK_LOCATION realIrpStack
;
2869 PIO_STACK_LOCATION realIrpNextStack
;
2870 PSCSI_REQUEST_BLOCK srb
= Context
;
2871 PIRP realIrp
= NULL
;
2876 // Extract the 'real' irp from the irpstack.
2879 realIrp
= (PIRP
) irpStack
->Parameters
.Others
.Argument2
;
2880 realIrpStack
= IoGetCurrentIrpStackLocation(realIrp
);
2881 realIrpNextStack
= IoGetNextIrpStackLocation(realIrp
);
2884 // Check SRB status for success of completing request.
2887 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
2890 "CdRomDeviceControlCompletion: Irp %lx, Srb %lx Real Irp %lx Status %lx\n",
2897 // Release the queue if it is frozen.
2900 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
2901 DebugPrint((2, "CdRomDeviceControlCompletion: Releasing Queue\n"));
2902 ScsiClassReleaseQueue(DeviceObject
);
2906 retry
= ScsiClassInterpretSenseInfo(DeviceObject
,
2908 irpStack
->MajorFunction
,
2909 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
,
2910 MAXIMUM_RETRIES
- ((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
),
2913 DebugPrint((2, "CdRomDeviceControlCompletion: IRP will %sbe retried\n",
2914 (retry
? "" : "not ")));
2917 // Some of the Device Controls need special cases on non-Success status's.
2920 if (realIrpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
) {
2921 if ((realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_GET_LAST_SESSION
) ||
2922 (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_READ_TOC
) ||
2923 (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_GET_CONTROL
) ||
2924 (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_GET_VOLUME
)) {
2926 if (status
== STATUS_DATA_OVERRUN
) {
2927 status
= STATUS_SUCCESS
;
2932 if (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_READ_Q_CHANNEL
) {
2933 PLAY_ACTIVE(deviceExtension
) = FALSE
;
2938 // If the status is verified required and the this request
2939 // should bypass verify required then retry the request.
2942 if (realIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
2943 status
== STATUS_VERIFY_REQUIRED
) {
2945 if (((realIrpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
) ||
2946 (realIrpStack
->MajorFunction
== IRP_MJ_INTERNAL_DEVICE_CONTROL
)) &&
2947 (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_CHECK_VERIFY
)) {
2950 // Update the geometry information, as the media could have changed.
2951 // The completion routine for this will complete the real irp and start
2955 status
= CdRomUpdateCapacity(deviceExtension
,realIrp
, NULL
);
2956 DebugPrint((2, "CdRomDeviceControlCompletion: [%lx] CdRomUpdateCapacity completed with status %lx\n", realIrp
, status
));
2957 ASSERT(status
== STATUS_PENDING
);
2959 return STATUS_MORE_PROCESSING_REQUIRED
;
2963 status
= STATUS_IO_DEVICE_ERROR
;
2969 if (retry
&& (realIrpNextStack
->Parameters
.Others
.Argument1
= (PVOID
)((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
-1))) {
2972 if (((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
)) {
2978 DebugPrint((1, "Retry request %lx - Calling StartIo\n", Irp
));
2981 ExFreePool(srb
->SenseInfoBuffer
);
2982 if (srb
->DataBuffer
) {
2983 ExFreePool(srb
->DataBuffer
);
2986 if (Irp
->MdlAddress
) {
2987 IoFreeMdl(Irp
->MdlAddress
);
2993 // Call StartIo directly since IoStartNextPacket hasn't been called,
2994 // the serialisation is still intact.
2997 ScsiCdRomStartIo(DeviceObject
, realIrp
);
2998 return STATUS_MORE_PROCESSING_REQUIRED
;
3003 // Exhausted retries. Fall through and complete the request with the appropriate status.
3010 // Set status for successful request.
3013 status
= STATUS_SUCCESS
;
3016 if (NT_SUCCESS(status
)) {
3018 switch (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
) {
3020 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
: {
3022 PREAD_CAPACITY_DATA readCapacityBuffer
= srb
->DataBuffer
;
3029 // Swizzle bytes from Read Capacity and translate into
3030 // the necessary geometry information in the device extension.
3033 tmp
= readCapacityBuffer
->BytesPerBlock
;
3034 ((PFOUR_BYTE
)&bps
)->Byte0
= ((PFOUR_BYTE
)&tmp
)->Byte3
;
3035 ((PFOUR_BYTE
)&bps
)->Byte1
= ((PFOUR_BYTE
)&tmp
)->Byte2
;
3036 ((PFOUR_BYTE
)&bps
)->Byte2
= ((PFOUR_BYTE
)&tmp
)->Byte1
;
3037 ((PFOUR_BYTE
)&bps
)->Byte3
= ((PFOUR_BYTE
)&tmp
)->Byte0
;
3040 // Insure that bps is a power of 2.
3041 // This corrects a problem with the HP 4020i CDR where it
3042 // returns an incorrect number for bytes per sector.
3048 lastBit
= (ULONG
) -1;
3056 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= bps
;
3059 "CdRomDeviceControlCompletion: Calculated bps %#x\n",
3060 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
));
3063 // Copy last sector in reverse byte order.
3066 tmp
= readCapacityBuffer
->LogicalBlockAddress
;
3067 ((PFOUR_BYTE
)&lastSector
)->Byte0
= ((PFOUR_BYTE
)&tmp
)->Byte3
;
3068 ((PFOUR_BYTE
)&lastSector
)->Byte1
= ((PFOUR_BYTE
)&tmp
)->Byte2
;
3069 ((PFOUR_BYTE
)&lastSector
)->Byte2
= ((PFOUR_BYTE
)&tmp
)->Byte1
;
3070 ((PFOUR_BYTE
)&lastSector
)->Byte3
= ((PFOUR_BYTE
)&tmp
)->Byte0
;
3073 // Calculate sector to byte shift.
3076 WHICH_BIT(bps
, deviceExtension
->SectorShift
);
3078 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Sector size is %d\n",
3079 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
));
3081 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Number of Sectors is %d\n",
3085 // Calculate media capacity in bytes.
3088 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(lastSector
+ 1);
3091 // Calculate number of cylinders.
3094 deviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
= (LONGLONG
)((lastSector
+ 1)/(32 * 64));
3096 deviceExtension
->PartitionLength
.QuadPart
=
3097 (deviceExtension
->PartitionLength
.QuadPart
<< deviceExtension
->SectorShift
);
3099 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
3102 // This device supports removable media.
3105 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= RemovableMedia
;
3110 // Assume media type is fixed disk.
3113 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= FixedMedia
;
3117 // Assume sectors per track are 32;
3120 deviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
= 32;
3123 // Assume tracks per cylinder (number of heads) is 64.
3126 deviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
= 64;
3129 // Copy the device extension's geometry info into the user buffer.
3132 RtlMoveMemory(realIrp
->AssociatedIrp
.SystemBuffer
,
3133 deviceExtension
->DiskGeometry
,
3134 sizeof(DISK_GEOMETRY
));
3137 // update information field.
3140 realIrp
->IoStatus
.Information
= sizeof(DISK_GEOMETRY
);
3144 case IOCTL_CDROM_CHECK_VERIFY
:
3146 if((realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_CHECK_VERIFY
) &&
3147 (realIrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
)) {
3149 *((PULONG
)realIrp
->AssociatedIrp
.SystemBuffer
) =
3150 physicalExtension
->MediaChangeCount
;
3151 realIrp
->IoStatus
.Information
= sizeof(ULONG
);
3153 realIrp
->IoStatus
.Information
= 0;
3156 DebugPrint((2, "CdRomDeviceControlCompletion: [%lx] completing CHECK_VERIFY buddy irp %lx\n", realIrp
, Irp
));
3159 case IOCTL_CDROM_GET_LAST_SESSION
:
3160 case IOCTL_CDROM_READ_TOC
: {
3162 PCDROM_TOC toc
= srb
->DataBuffer
;
3165 // Copy the device extension's geometry info into the user buffer.
3168 RtlMoveMemory(realIrp
->AssociatedIrp
.SystemBuffer
,
3170 srb
->DataTransferLength
);
3173 // update information field.
3176 realIrp
->IoStatus
.Information
= srb
->DataTransferLength
;
3180 case IOCTL_CDROM_PLAY_AUDIO_MSF
:
3182 PLAY_ACTIVE(deviceExtension
) = TRUE
;
3186 case IOCTL_CDROM_READ_Q_CHANNEL
: {
3188 PSUB_Q_CHANNEL_DATA userChannelData
= realIrp
->AssociatedIrp
.SystemBuffer
;
3190 PCDROM_SUB_Q_DATA_FORMAT inputBuffer
= realIrp
->AssociatedIrp
.SystemBuffer
;
3192 PSUB_Q_CHANNEL_DATA subQPtr
= srb
->DataBuffer
;
3195 switch( inputBuffer
->Format
) {
3197 case IOCTL_CDROM_CURRENT_POSITION
:
3198 DebugPrint((2,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr
->CurrentPosition
.Header
.AudioStatus
));
3199 DebugPrint((2,"CdRomDeviceControlCompletion: ADR = 0x%x\n", subQPtr
->CurrentPosition
.ADR
));
3200 DebugPrint((2,"CdRomDeviceControlCompletion: Control = 0x%x\n", subQPtr
->CurrentPosition
.Control
));
3201 DebugPrint((2,"CdRomDeviceControlCompletion: Track = %u\n", subQPtr
->CurrentPosition
.TrackNumber
));
3202 DebugPrint((2,"CdRomDeviceControlCompletion: Index = %u\n", subQPtr
->CurrentPosition
.IndexNumber
));
3203 DebugPrint((2,"CdRomDeviceControlCompletion: Absolute Address = %x\n", *((PULONG
)subQPtr
->CurrentPosition
.AbsoluteAddress
) ));
3204 DebugPrint((2,"CdRomDeviceControlCompletion: Relative Address = %x\n", *((PULONG
)subQPtr
->CurrentPosition
.TrackRelativeAddress
) ));
3207 case IOCTL_CDROM_MEDIA_CATALOG
:
3208 DebugPrint((2,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr
->MediaCatalog
.Header
.AudioStatus
));
3209 DebugPrint((2,"CdRomDeviceControlCompletion: Mcval is %u\n", subQPtr
->MediaCatalog
.Mcval
));
3212 case IOCTL_CDROM_TRACK_ISRC
:
3213 DebugPrint((2,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr
->TrackIsrc
.Header
.AudioStatus
));
3214 DebugPrint((2,"CdRomDeviceControlCompletion: Tcval is %u\n", subQPtr
->TrackIsrc
.Tcval
));
3221 // Update the play active status.
3224 if (subQPtr
->CurrentPosition
.Header
.AudioStatus
== AUDIO_STATUS_IN_PROGRESS
) {
3226 PLAY_ACTIVE(deviceExtension
) = TRUE
;
3230 PLAY_ACTIVE(deviceExtension
) = FALSE
;
3235 // Check if output buffer is large enough to contain
3239 if (realIrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
3240 srb
->DataTransferLength
) {
3242 srb
->DataTransferLength
=
3243 realIrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
3247 // Copy our buffer into users.
3250 RtlMoveMemory(userChannelData
,
3252 srb
->DataTransferLength
);
3254 realIrp
->IoStatus
.Information
= srb
->DataTransferLength
;
3258 case IOCTL_CDROM_PAUSE_AUDIO
:
3260 PLAY_ACTIVE(deviceExtension
) = FALSE
;
3261 realIrp
->IoStatus
.Information
= 0;
3264 case IOCTL_CDROM_RESUME_AUDIO
:
3266 realIrp
->IoStatus
.Information
= 0;
3269 case IOCTL_CDROM_SEEK_AUDIO_MSF
:
3271 realIrp
->IoStatus
.Information
= 0;
3274 case IOCTL_CDROM_STOP_AUDIO
:
3276 PLAY_ACTIVE(deviceExtension
) = FALSE
;
3278 realIrp
->IoStatus
.Information
= 0;
3281 case IOCTL_CDROM_GET_CONTROL
: {
3283 PCDROM_AUDIO_CONTROL audioControl
= srb
->DataBuffer
;
3284 PAUDIO_OUTPUT audioOutput
;
3285 ULONG bytesTransferred
;
3287 audioOutput
= ScsiClassFindModePage((PCHAR
)audioControl
,
3288 srb
->DataTransferLength
,
3289 CDROM_AUDIO_CONTROL_PAGE
,
3292 // Verify the page is as big as expected.
3295 bytesTransferred
= (PCHAR
) audioOutput
- (PCHAR
) audioControl
+
3296 sizeof(AUDIO_OUTPUT
);
3298 if (audioOutput
!= NULL
&&
3299 srb
->DataTransferLength
>= bytesTransferred
) {
3301 audioControl
->LbaFormat
= audioOutput
->LbaFormat
;
3303 audioControl
->LogicalBlocksPerSecond
=
3304 (audioOutput
->LogicalBlocksPerSecond
[0] << (UCHAR
)8) |
3305 audioOutput
->LogicalBlocksPerSecond
[1];
3307 realIrp
->IoStatus
.Information
= sizeof(CDROM_AUDIO_CONTROL
);
3310 realIrp
->IoStatus
.Information
= 0;
3311 status
= STATUS_INVALID_DEVICE_REQUEST
;
3316 case IOCTL_CDROM_GET_VOLUME
: {
3318 PAUDIO_OUTPUT audioOutput
;
3319 PVOLUME_CONTROL volumeControl
= srb
->DataBuffer
;
3320 ULONG i
,bytesTransferred
;
3322 audioOutput
= ScsiClassFindModePage((PCHAR
)volumeControl
,
3323 srb
->DataTransferLength
,
3324 CDROM_AUDIO_CONTROL_PAGE
,
3328 // Verify the page is as big as expected.
3331 bytesTransferred
= (PCHAR
) audioOutput
- (PCHAR
) volumeControl
+
3332 sizeof(AUDIO_OUTPUT
);
3334 if (audioOutput
!= NULL
&&
3335 srb
->DataTransferLength
>= bytesTransferred
) {
3337 for (i
=0; i
<4; i
++) {
3338 volumeControl
->PortVolume
[i
] =
3339 audioOutput
->PortOutput
[i
].Volume
;
3343 // Set bytes transferred in IRP.
3346 realIrp
->IoStatus
.Information
= sizeof(VOLUME_CONTROL
);
3349 realIrp
->IoStatus
.Information
= 0;
3350 status
= STATUS_INVALID_DEVICE_REQUEST
;
3356 case IOCTL_CDROM_SET_VOLUME
:
3358 realIrp
->IoStatus
.Information
= sizeof(VOLUME_CONTROL
);
3364 realIrp
->IoStatus
.Information
= 0;
3365 status
= STATUS_INVALID_DEVICE_REQUEST
;
3371 // Deallocate srb and sense buffer.
3375 if (srb
->DataBuffer
) {
3376 ExFreePool(srb
->DataBuffer
);
3378 if (srb
->SenseInfoBuffer
) {
3379 ExFreePool(srb
->SenseInfoBuffer
);
3384 if (realIrp
->PendingReturned
) {
3385 IoMarkIrpPending(realIrp
);
3388 if (Irp
->MdlAddress
) {
3389 IoFreeMdl(Irp
->MdlAddress
);
3395 // Set status in completing IRP.
3398 realIrp
->IoStatus
.Status
= status
;
3401 // Set the hard error if necessary.
3404 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
3407 // Store DeviceObject for filesystem, and clear
3408 // in IoStatus.Information field.
3411 DebugPrint((1, "CdRomDeviceCompletion - Setting Hard Error on realIrp %lx\n",
3413 IoSetHardErrorOrVerifyDevice(realIrp
, DeviceObject
);
3414 realIrp
->IoStatus
.Information
= 0;
3417 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
3419 IoStartNextPacket(DeviceObject
, FALSE
);
3421 return STATUS_MORE_PROCESSING_REQUIRED
;
3426 CdRomSetVolumeIntermediateCompletion(
3427 IN PDEVICE_OBJECT DeviceObject
,
3432 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3433 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3434 PCDROM_DATA cdData
= (PCDROM_DATA
)(deviceExtension
+ 1);
3435 BOOLEAN use6Byte
= cdData
->XAFlags
& XA_USE_6_BYTE
;
3436 PIO_STACK_LOCATION realIrpStack
;
3437 PIO_STACK_LOCATION realIrpNextStack
;
3438 PSCSI_REQUEST_BLOCK srb
= Context
;
3439 PIRP realIrp
= NULL
;
3444 // Extract the 'real' irp from the irpstack.
3447 realIrp
= (PIRP
) irpStack
->Parameters
.Others
.Argument2
;
3448 realIrpStack
= IoGetCurrentIrpStackLocation(realIrp
);
3449 realIrpNextStack
= IoGetNextIrpStackLocation(realIrp
);
3452 // Check SRB status for success of completing request.
3455 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
3458 "CdRomSetVolumeIntermediateCompletion: Irp %lx, Srb %lx Real Irp\n",
3464 // Release the queue if it is frozen.
3467 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
3468 ScsiClassReleaseQueue(DeviceObject
);
3472 retry
= ScsiClassInterpretSenseInfo(DeviceObject
,
3474 irpStack
->MajorFunction
,
3475 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
,
3476 MAXIMUM_RETRIES
- ((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
),
3479 if (status
== STATUS_DATA_OVERRUN
) {
3480 status
= STATUS_SUCCESS
;
3485 // If the status is verified required and the this request
3486 // should bypass verify required then retry the request.
3489 if (realIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
3490 status
== STATUS_VERIFY_REQUIRED
) {
3492 status
= STATUS_IO_DEVICE_ERROR
;
3496 if (retry
&& (realIrpNextStack
->Parameters
.Others
.Argument1
= (PVOID
)((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
-1))) {
3498 if (((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
)) {
3504 DebugPrint((1, "Retry request %lx - Calling StartIo\n", Irp
));
3507 ExFreePool(srb
->SenseInfoBuffer
);
3508 ExFreePool(srb
->DataBuffer
);
3510 if (Irp
->MdlAddress
) {
3511 IoFreeMdl(Irp
->MdlAddress
);
3517 // Call StartIo directly since IoStartNextPacket hasn't been called,
3518 // the serialisation is still intact.
3520 ScsiCdRomStartIo(DeviceObject
, realIrp
);
3521 return STATUS_MORE_PROCESSING_REQUIRED
;
3526 // Exhausted retries. Fall through and complete the request with the appropriate status.
3533 // Set status for successful request.
3536 status
= STATUS_SUCCESS
;
3539 if (NT_SUCCESS(status
)) {
3541 PAUDIO_OUTPUT audioInput
= NULL
;
3542 PAUDIO_OUTPUT audioOutput
;
3543 PVOLUME_CONTROL volumeControl
= realIrp
->AssociatedIrp
.SystemBuffer
;
3544 ULONG i
,bytesTransferred
,headerLength
;
3548 audioInput
= ScsiClassFindModePage((PCHAR
)srb
->DataBuffer
,
3549 srb
->DataTransferLength
,
3550 CDROM_AUDIO_CONTROL_PAGE
,
3554 // Check to make sure the mode sense data is valid before we go on
3557 if(audioInput
== NULL
) {
3559 DebugPrint((1, "Mode Sense Page %d not found\n",
3560 CDROM_AUDIO_CONTROL_PAGE
));
3562 realIrp
->IoStatus
.Information
= 0;
3563 realIrp
->IoStatus
.Status
= STATUS_IO_DEVICE_ERROR
;
3564 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
3565 ExFreePool(srb
->SenseInfoBuffer
);
3567 IoFreeMdl(Irp
->MdlAddress
);
3569 return STATUS_MORE_PROCESSING_REQUIRED
;
3573 headerLength
= sizeof(MODE_PARAMETER_HEADER
);
3575 headerLength
= sizeof(MODE_PARAMETER_HEADER10
);
3578 bytesTransferred
= sizeof(AUDIO_OUTPUT
) + headerLength
;
3581 // Allocate a new buffer for the mode select.
3584 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, bytesTransferred
);
3587 realIrp
->IoStatus
.Information
= 0;
3588 realIrp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3589 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
3590 ExFreePool(srb
->SenseInfoBuffer
);
3592 IoFreeMdl(Irp
->MdlAddress
);
3594 return STATUS_MORE_PROCESSING_REQUIRED
;
3597 RtlZeroMemory(dataBuffer
, bytesTransferred
);
3600 // Rebuild the data buffer to include the user requested values.
3603 audioOutput
= (PAUDIO_OUTPUT
) ((PCHAR
) dataBuffer
+ headerLength
);
3605 for (i
=0; i
<4; i
++) {
3606 audioOutput
->PortOutput
[i
].Volume
=
3607 volumeControl
->PortVolume
[i
];
3608 audioOutput
->PortOutput
[i
].ChannelSelection
=
3609 audioInput
->PortOutput
[i
].ChannelSelection
;
3612 audioOutput
->CodePage
= CDROM_AUDIO_CONTROL_PAGE
;
3613 audioOutput
->ParameterLength
= sizeof(AUDIO_OUTPUT
) - 2;
3614 audioOutput
->Immediate
= MODE_SELECT_IMMEDIATE
;
3617 // Free the old data buffer, mdl.
3620 ExFreePool(srb
->DataBuffer
);
3621 IoFreeMdl(Irp
->MdlAddress
);
3627 cdb
= (PCDB
)srb
->Cdb
;
3628 RtlZeroMemory(cdb
, CDB12GENERIC_LENGTH
);
3630 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
3631 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
3632 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_OUT
);
3633 srb
->DataTransferLength
= bytesTransferred
;
3637 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
3638 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
) bytesTransferred
;
3639 cdb
->MODE_SELECT
.PFBit
= 1;
3643 cdb
->MODE_SELECT10
.OperationCode
= SCSIOP_MODE_SELECT10
;
3644 cdb
->MODE_SELECT10
.ParameterListLength
[0] = (UCHAR
) (bytesTransferred
>> 8);
3645 cdb
->MODE_SELECT10
.ParameterListLength
[1] = (UCHAR
) (bytesTransferred
& 0xFF);
3646 cdb
->MODE_SELECT10
.PFBit
= 1;
3647 srb
->CdbLength
= 10;
3654 Irp
->MdlAddress
= IoAllocateMdl(dataBuffer
,
3660 if (!Irp
->MdlAddress
) {
3661 realIrp
->IoStatus
.Information
= 0;
3662 realIrp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3663 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
3664 ExFreePool(srb
->SenseInfoBuffer
);
3666 ExFreePool(dataBuffer
);
3668 return STATUS_MORE_PROCESSING_REQUIRED
;
3672 MmBuildMdlForNonPagedPool(Irp
->MdlAddress
);
3673 srb
->DataBuffer
= dataBuffer
;
3675 irpStack
= IoGetNextIrpStackLocation(Irp
);
3676 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
3677 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
3678 irpStack
->Parameters
.Scsi
.Srb
= srb
;
3681 // reset the irp completion.
3684 IoSetCompletionRoutine(Irp
,
3685 CdRomDeviceControlCompletion
,
3691 // Call the port driver.
3694 IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
3696 return STATUS_MORE_PROCESSING_REQUIRED
;
3700 // Deallocate srb and sense buffer.
3704 if (srb
->DataBuffer
) {
3705 ExFreePool(srb
->DataBuffer
);
3707 if (srb
->SenseInfoBuffer
) {
3708 ExFreePool(srb
->SenseInfoBuffer
);
3713 if (Irp
->PendingReturned
) {
3714 IoMarkIrpPending(Irp
);
3717 if (realIrp
->PendingReturned
) {
3718 IoMarkIrpPending(realIrp
);
3721 if (Irp
->MdlAddress
) {
3722 IoFreeMdl(Irp
->MdlAddress
);
3728 // Set status in completing IRP.
3731 realIrp
->IoStatus
.Status
= status
;
3734 // Set the hard error if necessary.
3737 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
3740 // Store DeviceObject for filesystem, and clear
3741 // in IoStatus.Information field.
3744 IoSetHardErrorOrVerifyDevice(realIrp
, DeviceObject
);
3745 realIrp
->IoStatus
.Information
= 0;
3748 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
3750 IoStartNextPacket(DeviceObject
, FALSE
);
3752 return STATUS_MORE_PROCESSING_REQUIRED
;
3758 CdRomSwitchModeCompletion(
3759 IN PDEVICE_OBJECT DeviceObject
,
3764 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3765 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3766 PCDROM_DATA cdData
= (PCDROM_DATA
)(deviceExtension
+ 1);
3767 PIO_STACK_LOCATION realIrpStack
;
3768 PIO_STACK_LOCATION realIrpNextStack
;
3769 PSCSI_REQUEST_BLOCK srb
= Context
;
3770 PIRP realIrp
= NULL
;
3775 // Extract the 'real' irp from the irpstack.
3778 realIrp
= (PIRP
) irpStack
->Parameters
.Others
.Argument2
;
3779 realIrpStack
= IoGetCurrentIrpStackLocation(realIrp
);
3780 realIrpNextStack
= IoGetNextIrpStackLocation(realIrp
);
3783 // Check SRB status for success of completing request.
3786 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
3789 "CdRomSetVolumeIntermediateCompletion: Irp %lx, Srb %lx Real Irp\n",
3795 // Release the queue if it is frozen.
3798 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
3799 ScsiClassReleaseQueue(DeviceObject
);
3803 retry
= ScsiClassInterpretSenseInfo(DeviceObject
,
3805 irpStack
->MajorFunction
,
3806 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
,
3807 MAXIMUM_RETRIES
- ((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
),
3811 // If the status is verified required and the this request
3812 // should bypass verify required then retry the request.
3815 if (realIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
3816 status
== STATUS_VERIFY_REQUIRED
) {
3818 status
= STATUS_IO_DEVICE_ERROR
;
3822 if (retry
&& (realIrpNextStack
->Parameters
.Others
.Argument1
= (PVOID
)((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
-1))) {
3824 if (((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
)) {
3830 DebugPrint((1, "Retry request %lx - Calling StartIo\n", Irp
));
3833 ExFreePool(srb
->SenseInfoBuffer
);
3834 ExFreePool(srb
->DataBuffer
);
3836 if (Irp
->MdlAddress
) {
3837 IoFreeMdl(Irp
->MdlAddress
);
3843 // Call StartIo directly since IoStartNextPacket hasn't been called,
3844 // the serialisation is still intact.
3847 ScsiCdRomStartIo(DeviceObject
, realIrp
);
3848 return STATUS_MORE_PROCESSING_REQUIRED
;
3853 // Exhausted retries. Fall through and complete the request with the appropriate status.
3859 // Set status for successful request.
3862 status
= STATUS_SUCCESS
;
3865 if (NT_SUCCESS(status
)) {
3867 ULONG sectorSize
, startingSector
, transferByteCount
;
3871 // Update device ext. to show which mode we are currently using.
3874 sectorSize
= cdData
->u1
.BlockDescriptor
.BlockLength
[0] << 16;
3875 sectorSize
|= (cdData
->u1
.BlockDescriptor
.BlockLength
[1] << 8);
3876 sectorSize
|= (cdData
->u1
.BlockDescriptor
.BlockLength
[2]);
3878 cdData
->RawAccess
= (sectorSize
== RAW_SECTOR_SIZE
) ? TRUE
: FALSE
;
3881 // Free the old data buffer, mdl.
3884 ExFreePool(srb
->DataBuffer
);
3885 IoFreeMdl(Irp
->MdlAddress
);
3892 cdb
= (PCDB
)srb
->Cdb
;
3893 RtlZeroMemory(cdb
, CDB12GENERIC_LENGTH
);
3896 if (cdData
->RawAccess
) {
3898 PRAW_READ_INFO rawReadInfo
=
3899 (PRAW_READ_INFO
)realIrpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
3901 ULONG maximumTransferLength
;
3902 ULONG transferPages
;
3905 // Calculate starting offset.
3908 startingSector
= (ULONG
)(rawReadInfo
->DiskOffset
.QuadPart
>> deviceExtension
->SectorShift
);
3909 transferByteCount
= rawReadInfo
->SectorCount
* RAW_SECTOR_SIZE
;
3910 maximumTransferLength
= deviceExtension
->PortCapabilities
->MaximumTransferLength
;
3911 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(realIrp
->MdlAddress
),
3915 // Determine if request is within limits imposed by miniport.
3916 // If the request is larger than the miniport's capabilities, split it.
3919 if (transferByteCount
> maximumTransferLength
||
3920 transferPages
> deviceExtension
->PortCapabilities
->MaximumPhysicalPages
) {
3922 realIrp
->IoStatus
.Information
= 0;
3923 realIrp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
3924 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
3926 ExFreePool(srb
->SenseInfoBuffer
);
3927 ExFreePool(srb
->DataBuffer
);
3929 IoFreeMdl(Irp
->MdlAddress
);
3932 IoStartNextPacket(DeviceObject
, FALSE
);
3934 return STATUS_MORE_PROCESSING_REQUIRED
;
3937 srb
->OriginalRequest
= realIrp
;
3938 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
3939 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
3940 srb
->DataTransferLength
= transferByteCount
;
3941 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
3942 srb
->CdbLength
= 10;
3943 srb
->DataBuffer
= MmGetMdlVirtualAddress(realIrp
->MdlAddress
);
3945 if (rawReadInfo
->TrackMode
== CDDA
) {
3946 if (cdData
->XAFlags
& PLEXTOR_CDDA
) {
3948 srb
->CdbLength
= 12;
3950 cdb
->PLXTR_READ_CDDA
.LogicalUnitNumber
= deviceExtension
->Lun
;
3951 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
3952 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
3953 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
3954 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
3956 cdb
->PLXTR_READ_CDDA
.TransferBlockByte3
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
3957 cdb
->PLXTR_READ_CDDA
.TransferBlockByte2
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
3958 cdb
->PLXTR_READ_CDDA
.TransferBlockByte1
= 0;
3959 cdb
->PLXTR_READ_CDDA
.TransferBlockByte0
= 0;
3961 cdb
->PLXTR_READ_CDDA
.SubCode
= 0;
3962 cdb
->PLXTR_READ_CDDA
.OperationCode
= 0xD8;
3964 } else if (cdData
->XAFlags
& NEC_CDDA
) {
3966 cdb
->NEC_READ_CDDA
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
3967 cdb
->NEC_READ_CDDA
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
3968 cdb
->NEC_READ_CDDA
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
3969 cdb
->NEC_READ_CDDA
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
3971 cdb
->NEC_READ_CDDA
.TransferBlockByte1
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
3972 cdb
->NEC_READ_CDDA
.TransferBlockByte0
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
3974 cdb
->NEC_READ_CDDA
.OperationCode
= 0xD4;
3977 cdb
->CDB10
.LogicalUnitNumber
= deviceExtension
->Lun
;
3979 cdb
->CDB10
.TransferBlocksMsb
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
3980 cdb
->CDB10
.TransferBlocksLsb
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
3982 cdb
->CDB10
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
3983 cdb
->CDB10
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
3984 cdb
->CDB10
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
3985 cdb
->CDB10
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
3987 cdb
->CDB10
.OperationCode
= SCSIOP_READ
;
3990 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
3993 irpStack
= IoGetNextIrpStackLocation(realIrp
);
3994 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
3995 irpStack
->Parameters
.Scsi
.Srb
= srb
;
3997 if (!(irpStack
->Parameters
.Others
.Argument1
)) {
4000 // Only jam this in if it doesn't exist. The completion routines can
4001 // call StartIo directly in the case of retries and resetting it will
4002 // cause infinite loops.
4005 irpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
4009 // Set up IoCompletion routine address.
4012 IoSetCompletionRoutine(realIrp
,
4020 ULONG maximumTransferLength
= deviceExtension
->PortCapabilities
->MaximumTransferLength
;
4021 ULONG transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(realIrp
->MdlAddress
),
4022 realIrpStack
->Parameters
.Read
.Length
);
4024 // Back to cooked sectors. Build and send a normal read.
4025 // The real work for setting offsets and checking for splitrequests was
4029 if ((realIrpStack
->Parameters
.Read
.Length
> maximumTransferLength
) ||
4030 (transferPages
> deviceExtension
->PortCapabilities
->MaximumPhysicalPages
)) {
4033 // Request needs to be split. Completion of each portion of the request will
4034 // fire off the next portion. The final request will signal Io to send a new request.
4037 ScsiClassSplitRequest(DeviceObject
, realIrp
, maximumTransferLength
);
4038 return STATUS_MORE_PROCESSING_REQUIRED
;
4043 // Build SRB and CDB for this IRP.
4046 ScsiClassBuildRequest(DeviceObject
, realIrp
);
4052 // Call the port driver.
4055 IoCallDriver(deviceExtension
->PortDeviceObject
, realIrp
);
4057 return STATUS_MORE_PROCESSING_REQUIRED
;
4061 // Update device Extension flags to indicate that XA isn't supported.
4064 cdData
->XAFlags
|= XA_NOT_SUPPORTED
;
4067 // Deallocate srb and sense buffer.
4071 if (srb
->DataBuffer
) {
4072 ExFreePool(srb
->DataBuffer
);
4074 if (srb
->SenseInfoBuffer
) {
4075 ExFreePool(srb
->SenseInfoBuffer
);
4080 if (Irp
->PendingReturned
) {
4081 IoMarkIrpPending(Irp
);
4084 if (realIrp
->PendingReturned
) {
4085 IoMarkIrpPending(realIrp
);
4088 if (Irp
->MdlAddress
) {
4089 IoFreeMdl(Irp
->MdlAddress
);
4095 // Set status in completing IRP.
4098 realIrp
->IoStatus
.Status
= status
;
4101 // Set the hard error if necessary.
4104 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
4107 // Store DeviceObject for filesystem, and clear
4108 // in IoStatus.Information field.
4111 IoSetHardErrorOrVerifyDevice(realIrp
, DeviceObject
);
4112 realIrp
->IoStatus
.Information
= 0;
4115 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
4117 IoStartNextPacket(DeviceObject
, FALSE
);
4119 return STATUS_MORE_PROCESSING_REQUIRED
;
4125 IN PDEVICE_OBJECT DeviceObject
,
4132 Routine Description:
4134 This routine executes when the port driver has completed a request.
4135 It looks at the SRB status in the completing SRB and if not success
4136 it checks for valid request sense buffer information. If valid, the
4137 info is used to update status with more precise message of type of
4138 error. This routine deallocates the SRB.
4142 DeviceObject - Supplies the device object which represents the logical
4145 Irp - Supplies the Irp which has completed.
4147 Context - Supplies a pointer to the SRB.
4156 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
4157 PIO_STACK_LOCATION irpNextStack
= IoGetNextIrpStackLocation(Irp
);
4158 PSCSI_REQUEST_BLOCK srb
= Context
;
4163 // Check SRB status for success of completing request.
4166 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
4168 DebugPrint((2,"ScsiClassIoComplete: IRP %lx, SRB %lx\n", Irp
, srb
));
4171 // Release the queue if it is frozen.
4174 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
4175 ScsiClassReleaseQueue(DeviceObject
);
4178 retry
= ScsiClassInterpretSenseInfo(
4181 irpStack
->MajorFunction
,
4182 irpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
? irpStack
->Parameters
.DeviceIoControl
.IoControlCode
: 0,
4183 MAXIMUM_RETRIES
- ((ULONG_PTR
)irpNextStack
->Parameters
.Others
.Argument1
),
4187 // If the status is verified required and the this request
4188 // should bypass verify required then retry the request.
4191 if (irpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
4192 status
== STATUS_VERIFY_REQUIRED
) {
4194 status
= STATUS_IO_DEVICE_ERROR
;
4198 if (retry
&& (irpNextStack
->Parameters
.Others
.Argument1
= (PVOID
)((ULONG_PTR
)irpNextStack
->Parameters
.Others
.Argument1
-1))) {
4200 if (((ULONG_PTR
)irpNextStack
->Parameters
.Others
.Argument1
)) {
4206 DebugPrint((1, "CdRomXACompletion: Retry request %lx - Calling StartIo\n", Irp
));
4209 ExFreePool(srb
->SenseInfoBuffer
);
4210 ExFreePool(srb
->DataBuffer
);
4214 // Call StartIo directly since IoStartNextPacket hasn't been called,
4215 // the serialisation is still intact.
4218 ScsiCdRomStartIo(DeviceObject
, Irp
);
4219 return STATUS_MORE_PROCESSING_REQUIRED
;
4224 // Exhausted retries. Fall through and complete the request with the appropriate status.
4230 // Set status for successful request.
4233 status
= STATUS_SUCCESS
;
4235 } // end if (SRB_STATUS(srb->SrbStatus) ...
4238 // Return SRB to nonpaged pool.
4244 // Set status in completing IRP.
4247 Irp
->IoStatus
.Status
= status
;
4250 // Set the hard error if necessary.
4253 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
4256 // Store DeviceObject for filesystem, and clear
4257 // in IoStatus.Information field.
4260 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
4261 Irp
->IoStatus
.Information
= 0;
4265 // If pending has be returned for this irp then mark the current stack as
4269 if (Irp
->PendingReturned
) {
4270 IoMarkIrpPending(Irp
);
4273 //IoCompleteRequest(Irp, IO_DISK_INCREMENT);
4274 IoStartNextPacket(DeviceObject
, FALSE
);
4282 IN PDEVICE_OBJECT DeviceObject
,
4288 Routine Description:
4290 This is the NT device control handler for CDROMs.
4294 DeviceObject - for this CDROM
4296 Irp - IO Request packet
4305 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
4306 PIO_STACK_LOCATION nextStack
;
4307 PKEVENT deviceControlEvent
;
4308 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4309 PCDROM_DATA cdData
= (PCDROM_DATA
)(deviceExtension
+1);
4310 SCSI_REQUEST_BLOCK srb
;
4321 // Zero the SRB on stack.
4324 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
4326 Irp
->IoStatus
.Information
= 0;
4329 // if this is a class driver ioctl then we need to change the base code
4330 // to IOCTL_CDROM_BASE so that the switch statement can handle it.
4332 // WARNING - currently the scsi class ioctl function codes are between
4333 // 0x200 & 0x300. this routine depends on that fact
4336 ioctlCode
= irpStack
->Parameters
.DeviceIoControl
.IoControlCode
;
4337 baseCode
= ioctlCode
>> 16;
4338 functionCode
= (ioctlCode
& (~0xffffc003)) >> 2;
4340 DebugPrint((1, "CdRomDeviceControl: Ioctl Code = %#08lx, Base Code = %#lx,"
4341 " Function Code = %#lx\n",
4347 if((functionCode
>= 0x200) && (functionCode
<= 0x300)) {
4349 ioctlCode
= (ioctlCode
& 0x0000ffff) | CTL_CODE(IOCTL_CDROM_BASE
, 0, 0, 0);
4351 DebugPrint((1, "CdRomDeviceControl: Class Code - new ioctl code is %#08lx\n",
4354 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= ioctlCode
;
4358 switch (ioctlCode
) {
4360 case IOCTL_CDROM_RAW_READ
: {
4362 LARGE_INTEGER startingOffset
;
4363 ULONG transferBytes
;
4364 ULONG startingSector
;
4365 PRAW_READ_INFO rawReadInfo
= (PRAW_READ_INFO
)irpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
4366 PUCHAR userData
= (PUCHAR
)Irp
->AssociatedIrp
.SystemBuffer
;
4369 // Ensure that XA reads are supported.
4372 if (cdData
->XAFlags
& XA_NOT_SUPPORTED
) {
4375 "CdRomDeviceControl: XA Reads not supported. Flags (%x)\n",
4378 status
= STATUS_INVALID_DEVICE_REQUEST
;
4383 // Check that ending sector is on disc and buffers are there and of
4387 if (rawReadInfo
== NULL
) {
4390 // Called from user space. Validate the buffers.
4393 rawReadInfo
= (PRAW_READ_INFO
)userData
;
4394 irpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
= (PVOID
)userData
;
4396 if (rawReadInfo
== NULL
) {
4398 DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (No extent info\n"));
4400 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
4402 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4403 return STATUS_INVALID_PARAMETER
;
4406 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
!= sizeof(RAW_READ_INFO
)) {
4408 DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (Invalid info buffer\n"));
4410 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
4412 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4413 return STATUS_INVALID_PARAMETER
;
4417 startingOffset
.QuadPart
= rawReadInfo
->DiskOffset
.QuadPart
;
4418 startingSector
= (ULONG
)(rawReadInfo
->DiskOffset
.QuadPart
>> deviceExtension
->SectorShift
);
4419 transferBytes
= rawReadInfo
->SectorCount
* RAW_SECTOR_SIZE
;
4421 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< transferBytes
) {
4423 DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (Bad buffer size)\n"));
4426 // Fail request with status of invalid parameters.
4429 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
4431 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4432 return STATUS_INVALID_PARAMETER
;
4435 if ((startingOffset
.QuadPart
+ transferBytes
) > deviceExtension
->PartitionLength
.QuadPart
) {
4437 DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (Request Out of Bounds)\n"));
4440 // Fail request with status of invalid parameters.
4443 status
= STATUS_INVALID_PARAMETER
;
4447 IoMarkIrpPending(Irp
);
4448 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4450 return STATUS_PENDING
;
4453 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
: {
4455 DebugPrint((2,"CdRomDeviceControl: Get drive geometry\n"));
4457 if ( irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
4458 sizeof( DISK_GEOMETRY
) ) {
4460 status
= STATUS_INFO_LENGTH_MISMATCH
;
4464 IoMarkIrpPending(Irp
);
4465 IoStartPacket(DeviceObject
,Irp
, NULL
,NULL
);
4467 return STATUS_PENDING
;
4470 case IOCTL_CDROM_GET_LAST_SESSION
:
4471 case IOCTL_CDROM_READ_TOC
: {
4474 // If the cd is playing music then reject this request.
4477 if (CdRomIsPlayActive(DeviceObject
)) {
4478 Irp
->IoStatus
.Status
= STATUS_DEVICE_BUSY
;
4479 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4480 return STATUS_DEVICE_BUSY
;
4483 IoMarkIrpPending(Irp
);
4484 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4486 return STATUS_PENDING
;
4489 case IOCTL_CDROM_PLAY_AUDIO_MSF
: {
4495 DebugPrint((2,"CdRomDeviceControl: Play audio MSF\n"));
4497 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
4498 sizeof(CDROM_PLAY_AUDIO_MSF
)) {
4501 // Indicate unsuccessful status.
4504 status
= STATUS_BUFFER_TOO_SMALL
;
4508 IoMarkIrpPending(Irp
);
4509 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4511 return STATUS_PENDING
;
4514 case IOCTL_CDROM_SEEK_AUDIO_MSF
: {
4521 DebugPrint((2,"CdRomDeviceControl: Seek audio MSF\n"));
4523 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
4524 sizeof(CDROM_SEEK_AUDIO_MSF
)) {
4527 // Indicate unsuccessful status.
4530 status
= STATUS_BUFFER_TOO_SMALL
;
4533 IoMarkIrpPending(Irp
);
4534 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4536 return STATUS_PENDING
;
4541 case IOCTL_CDROM_PAUSE_AUDIO
: {
4547 DebugPrint((2, "CdRomDeviceControl: Pause audio\n"));
4549 IoMarkIrpPending(Irp
);
4550 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4552 return STATUS_PENDING
;
4557 case IOCTL_CDROM_RESUME_AUDIO
: {
4563 DebugPrint((2, "CdRomDeviceControl: Resume audio\n"));
4565 IoMarkIrpPending(Irp
);
4566 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4568 return STATUS_PENDING
;
4571 case IOCTL_CDROM_READ_Q_CHANNEL
: {
4573 if(irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
4574 sizeof(CDROM_SUB_Q_DATA_FORMAT
)) {
4576 status
= STATUS_BUFFER_TOO_SMALL
;
4577 Irp
->IoStatus
.Information
= 0;
4581 IoMarkIrpPending(Irp
);
4582 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4584 return STATUS_PENDING
;
4587 case IOCTL_CDROM_GET_CONTROL
: {
4589 DebugPrint((2, "CdRomDeviceControl: Get audio control\n"));
4592 // Verify user buffer is large enough for the data.
4595 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
4596 sizeof(CDROM_AUDIO_CONTROL
)) {
4599 // Indicate unsuccessful status and no data transferred.
4602 status
= STATUS_BUFFER_TOO_SMALL
;
4603 Irp
->IoStatus
.Information
= 0;
4608 IoMarkIrpPending(Irp
);
4609 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4611 return STATUS_PENDING
;
4615 case IOCTL_CDROM_GET_VOLUME
: {
4617 DebugPrint((2, "CdRomDeviceControl: Get volume control\n"));
4620 // Verify user buffer is large enough for data.
4623 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
4624 sizeof(VOLUME_CONTROL
)) {
4627 // Indicate unsuccessful status and no data transferred.
4630 status
= STATUS_BUFFER_TOO_SMALL
;
4631 Irp
->IoStatus
.Information
= 0;
4635 IoMarkIrpPending(Irp
);
4636 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4638 return STATUS_PENDING
;
4642 case IOCTL_CDROM_SET_VOLUME
: {
4644 DebugPrint((2, "CdRomDeviceControl: Set volume control\n"));
4646 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
4647 sizeof(VOLUME_CONTROL
)) {
4650 // Indicate unsuccessful status.
4653 status
= STATUS_BUFFER_TOO_SMALL
;
4657 IoMarkIrpPending(Irp
);
4658 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4660 return STATUS_PENDING
;
4664 case IOCTL_CDROM_STOP_AUDIO
: {
4670 DebugPrint((2, "CdRomDeviceControl: Stop audio\n"));
4672 IoMarkIrpPending(Irp
);
4673 IoStartPacket(DeviceObject
,Irp
, NULL
,NULL
);
4675 return STATUS_PENDING
;
4678 case IOCTL_CDROM_CHECK_VERIFY
: {
4679 DebugPrint((1, "CdRomDeviceControl: [%lx] Check Verify\n", Irp
));
4680 IoMarkIrpPending(Irp
);
4682 if((irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
) &&
4683 (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))) {
4685 DebugPrint((1, "CdRomDeviceControl: Check Verify: media count "
4686 "buffer too small\n"));
4688 status
= STATUS_BUFFER_TOO_SMALL
;
4692 IoStartPacket(DeviceObject
,Irp
, NULL
,NULL
);
4694 return STATUS_PENDING
;
4700 // allocate an event and stuff it into our stack location.
4703 deviceControlEvent
= ExAllocatePool(NonPagedPool
, sizeof(KEVENT
));
4705 if(!deviceControlEvent
) {
4707 status
= STATUS_INSUFFICIENT_RESOURCES
;
4711 PIO_STACK_LOCATION currentStack
;
4713 KeInitializeEvent(deviceControlEvent
, NotificationEvent
, FALSE
);
4715 currentStack
= IoGetCurrentIrpStackLocation(Irp
);
4716 nextStack
= IoGetNextIrpStackLocation(Irp
);
4719 // Copy the stack down a notch
4722 *nextStack
= *currentStack
;
4724 IoSetCompletionRoutine(
4726 CdRomClassIoctlCompletion
,
4733 IoSetNextIrpStackLocation(Irp
);
4735 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4736 Irp
->IoStatus
.Information
= 0;
4739 // Override volume verifies on this stack location so that we
4740 // will be forced through the synchronization. Once this location
4741 // goes away we get the old value back
4744 nextStack
->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
4746 IoMarkIrpPending(Irp
);
4748 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4751 // Wait for CdRomClassIoctlCompletion to set the event. This
4752 // ensures serialization remains intact for these unhandled device
4756 KeWaitForSingleObject(
4763 ExFreePool(deviceControlEvent
);
4765 DebugPrint((2, "CdRomDeviceControl: irp %#08lx synchronized\n", Irp
));
4768 // If an error occured then propagate that back up - we are no longer
4769 // guaranteed synchronization and the upper layers will have to
4772 // If no error occured, call down to the class driver directly
4773 // then start up the next request.
4776 if(Irp
->IoStatus
.Status
== STATUS_SUCCESS
) {
4778 status
= ScsiClassDeviceControl(DeviceObject
, Irp
);
4780 KeRaiseIrql(DISPATCH_LEVEL
, &irql
);
4782 IoStartNextPacket(DeviceObject
, FALSE
);
4793 if (status
== STATUS_VERIFY_REQUIRED
) {
4796 // If the status is verified required and this request
4797 // should bypass verify required then retry the request.
4800 if (irpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
) {
4802 status
= STATUS_IO_DEVICE_ERROR
;
4808 if (IoIsErrorUserInduced(status
)) {
4810 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
4815 // Update IRP with completion status.
4818 Irp
->IoStatus
.Status
= status
;
4821 // Complete the request.
4824 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
4825 DebugPrint((2, "CdRomDeviceControl: Status is %lx\n", status
));
4828 } // end ScsiCdRomDeviceControl()
4833 PDEVICE_OBJECT DeviceObject
,
4834 PINQUIRYDATA InquiryData
,
4835 PIO_SCSI_CAPABILITIES PortCapabilities
4840 Routine Description:
4842 This function checks to see if an SCSI logical unit requires an special
4843 initialization or error processing.
4847 DeviceObject - Supplies the device object to be tested.
4849 InquiryData - Supplies the inquiry data returned by the device of interest.
4851 PortCapabilities - Supplies the capabilities of the device object.
4860 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4861 PCDROM_DATA cdData
= (PCDROM_DATA
)(deviceExtension
+1);
4864 // Look for a Hitachi CDR-1750. Read-ahead must be disabled in order
4865 // to get this cdrom drive to work on scsi adapters that use PIO.
4868 if ((strncmp((PCHAR
)InquiryData
->VendorId
, "HITACHI CDR-1750S", strlen("HITACHI CDR-1750S")) == 0 ||
4869 strncmp((PCHAR
)InquiryData
->VendorId
, "HITACHI CDR-3650/1650S", strlen("HITACHI CDR-3650/1650S")) == 0)
4870 && PortCapabilities
->AdapterUsesPio
) {
4872 DebugPrint((1, "CdRom ScanForSpecial: Found Hitachi CDR-1750S.\n"));
4875 // Setup an error handler to reinitialize the cd rom after it is reset.
4878 deviceExtension
->ClassError
= HitachProcessError
;
4880 } else if (( RtlCompareMemory( InquiryData
->VendorId
,"FUJITSU", 7 ) == 7 ) &&
4881 (( RtlCompareMemory( InquiryData
->ProductId
,"FMCD-101", 8 ) == 8 ) ||
4882 ( RtlCompareMemory( InquiryData
->ProductId
,"FMCD-102", 8 ) == 8 ))) {
4885 // When Read command is issued to FMCD-101 or FMCD-102 and there is a music
4886 // cd in it. It takes longer time than SCSI_CDROM_TIMEOUT before returning
4890 deviceExtension
->TimeOutValue
= 20;
4892 } else if (( RtlCompareMemory( InquiryData
->VendorId
,"TOSHIBA", 7) == 7) &&
4893 (( RtlCompareMemory( InquiryData
->ProductId
,"CD-ROM XM-34", 12) == 12))) {
4895 SCSI_REQUEST_BLOCK srb
;
4902 // Set the density code and the error handler.
4905 length
= (sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH
);
4907 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
4910 // Build the MODE SENSE CDB.
4914 cdb
= (PCDB
)srb
.Cdb
;
4917 // Set timeout value from device extension.
4920 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
4922 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
4923 cdb
->MODE_SENSE
.PageCode
= 0x1;
4924 cdb
->MODE_SENSE
.AllocationLength
= (UCHAR
)length
;
4926 buffer
= ExAllocatePool(NonPagedPoolCacheAligned
, (sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH
));
4931 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
4937 ((PERROR_RECOVERY_DATA
)buffer
)->BlockDescriptor
.DensityCode
= 0x83;
4938 ((PERROR_RECOVERY_DATA
)buffer
)->Header
.ModeDataLength
= 0x0;
4940 RtlCopyMemory(&cdData
->u1
.Header
, buffer
, sizeof(ERROR_RECOVERY_DATA
));
4942 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
4945 // Build the MODE SENSE CDB.
4949 cdb
= (PCDB
)srb
.Cdb
;
4952 // Set timeout value from device extension.
4955 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
4957 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
4958 cdb
->MODE_SELECT
.PFBit
= 1;
4959 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)length
;
4961 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
4967 if (!NT_SUCCESS(status
)) {
4969 "Cdrom.ScanForSpecial: Setting density code on Toshiba failed [%x]\n",
4973 deviceExtension
->ClassError
= ToshibaProcessError
;
4980 // Determine special CD-DA requirements.
4983 if (RtlCompareMemory( InquiryData
->VendorId
,"PLEXTOR",7) == 7) {
4984 cdData
->XAFlags
|= PLEXTOR_CDDA
;
4985 } else if (RtlCompareMemory ( InquiryData
->VendorId
,"NEC",3) == 3) {
4986 cdData
->XAFlags
|= NEC_CDDA
;
4995 PDEVICE_OBJECT DeviceObject
,
4996 PSCSI_REQUEST_BLOCK Srb
,
5002 Routine Description:
5004 This routine checks the type of error. If the error indicates CD-ROM the
5005 CD-ROM needs to be reinitialized then a Mode sense command is sent to the
5006 device. This command disables read-ahead for the device.
5010 DeviceObject - Supplies a pointer to the device object.
5012 Srb - Supplies a pointer to the failing Srb.
5025 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
5026 PSENSE_DATA senseBuffer
= Srb
->SenseInfoBuffer
;
5027 LARGE_INTEGER largeInt
;
5029 PIO_STACK_LOCATION irpStack
;
5031 PSCSI_REQUEST_BLOCK srb
;
5032 PCOMPLETION_CONTEXT context
;
5036 UNREFERENCED_PARAMETER(Status
);
5037 UNREFERENCED_PARAMETER(Retry
);
5039 largeInt
.QuadPart
= (LONGLONG
) 1;
5042 // Check the status. The initialization command only needs to be sent
5043 // if UNIT ATTENTION is returned.
5046 if (!(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
)) {
5049 // The drive does not require reinitialization.
5056 // Found a bad HITACHI cd-rom. These devices do not work with PIO
5057 // adapters when read-ahead is enabled. Read-ahead is disabled by
5058 // a mode select command. The mode select page code is zero and the
5059 // length is 6 bytes. All of the other bytes should be zero.
5063 if ((senseBuffer
->SenseKey
& 0xf) == SCSI_SENSE_UNIT_ATTENTION
) {
5065 DebugPrint((1, "HitachiProcessError: Reinitializing the CD-ROM.\n"));
5068 // Send the special mode select command to disable read-ahead
5069 // on the CD-ROM reader.
5072 alignment
= DeviceObject
->AlignmentRequirement
?
5073 DeviceObject
->AlignmentRequirement
: 1;
5075 context
= ExAllocatePool(
5077 sizeof(COMPLETION_CONTEXT
) + HITACHI_MODE_DATA_SIZE
+ alignment
5080 if (context
== NULL
) {
5083 // If there is not enough memory to fulfill this request,
5084 // simply return. A subsequent retry will fail and another
5085 // chance to start the unit.
5091 context
->DeviceObject
= DeviceObject
;
5092 srb
= &context
->Srb
;
5094 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
5097 // Write length to SRB.
5100 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
5103 // Set up SCSI bus address.
5106 srb
->PathId
= deviceExtension
->PathId
;
5107 srb
->TargetId
= deviceExtension
->TargetId
;
5108 srb
->Lun
= deviceExtension
->Lun
;
5110 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
5111 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
5114 // Set the transfer length.
5117 srb
->DataTransferLength
= HITACHI_MODE_DATA_SIZE
;
5118 srb
->SrbFlags
= SRB_FLAGS_DATA_OUT
| SRB_FLAGS_DISABLE_AUTOSENSE
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
5121 // The data buffer must be aligned.
5124 srb
->DataBuffer
= (PVOID
) (((ULONG_PTR
) (context
+ 1) + (alignment
- 1)) &
5129 // Build the HITACHI read-ahead mode select CDB.
5133 cdb
= (PCDB
)srb
->Cdb
;
5134 cdb
->MODE_SENSE
.LogicalUnitNumber
= srb
->Lun
;
5135 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SELECT
;
5136 cdb
->MODE_SENSE
.AllocationLength
= HITACHI_MODE_DATA_SIZE
;
5139 // Initialize the mode sense data.
5142 modePage
= srb
->DataBuffer
;
5144 RtlZeroMemory(modePage
, HITACHI_MODE_DATA_SIZE
);
5147 // Set the page length field to 6.
5153 // Build the asynchronous request to be sent to the port driver.
5156 irp
= IoBuildAsynchronousFsdRequest(IRP_MJ_WRITE
,
5159 srb
->DataTransferLength
,
5163 IoSetCompletionRoutine(irp
,
5164 (PIO_COMPLETION_ROUTINE
)ScsiClassAsynchronousCompletion
,
5170 irpStack
= IoGetNextIrpStackLocation(irp
);
5172 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
5174 srb
->OriginalRequest
= irp
;
5177 // Save SRB address in next stack for port driver.
5180 irpStack
->Parameters
.Scsi
.Srb
= (PVOID
)srb
;
5183 // Set up IRP Address.
5186 (VOID
)IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
5193 ToshibaProcessErrorCompletion(
5194 PDEVICE_OBJECT DeviceObject
,
5201 Routine Description:
5203 Completion routine for the ClassError routine to handle older Toshiba units
5204 that require setting the density code.
5208 DeviceObject - Supplies a pointer to the device object.
5210 Irp - Pointer to irp created to set the density code.
5212 Context - Supplies a pointer to the Mode Select Srb.
5217 STATUS_MORE_PROCESSING_REQUIRED
5223 PSCSI_REQUEST_BLOCK srb
= Context
;
5226 // Check for a frozen queue.
5229 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
5232 // Unfreeze the queue getting the device object from the context.
5235 ScsiClassReleaseQueue(DeviceObject
);
5239 // Free all of the allocations.
5242 ExFreePool(srb
->DataBuffer
);
5244 IoFreeMdl(Irp
->MdlAddress
);
5248 // Indicate the I/O system should stop processing the Irp completion.
5251 return STATUS_MORE_PROCESSING_REQUIRED
;
5256 ToshibaProcessError(
5257 PDEVICE_OBJECT DeviceObject
,
5258 PSCSI_REQUEST_BLOCK Srb
,
5265 Routine Description:
5267 This routine checks the type of error. If the error indicates a unit attention,
5268 the density code needs to be set via a Mode select command.
5272 DeviceObject - Supplies a pointer to the device object.
5274 Srb - Supplies a pointer to the failing Srb.
5287 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
5288 PCDROM_DATA cdData
= (PCDROM_DATA
)(deviceExtension
+1);
5289 PSENSE_DATA senseBuffer
= Srb
->SenseInfoBuffer
;
5290 PIO_STACK_LOCATION irpStack
;
5292 PSCSI_REQUEST_BLOCK srb
;
5298 if (!(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
)) {
5303 // The Toshiba's require the density code to be set on power up and media changes.
5306 if ((senseBuffer
->SenseKey
& 0xf) == SCSI_SENSE_UNIT_ATTENTION
) {
5309 irp
= IoAllocateIrp((CCHAR
)(deviceExtension
->DeviceObject
->StackSize
+1),
5316 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
5323 length
= sizeof(ERROR_RECOVERY_DATA
);
5324 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, length
);
5331 irp
->MdlAddress
= IoAllocateMdl(dataBuffer
,
5337 if (!irp
->MdlAddress
) {
5339 ExFreePool(dataBuffer
);
5348 MmBuildMdlForNonPagedPool(irp
->MdlAddress
);
5350 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
5352 srb
->DataBuffer
= dataBuffer
;
5353 cdb
= (PCDB
)srb
->Cdb
;
5359 IoSetNextIrpStackLocation(irp
);
5360 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
5361 irp
->IoStatus
.Information
= 0;
5363 irp
->UserBuffer
= NULL
;
5366 // Save the device object and irp in a private stack location.
5369 irpStack
= IoGetCurrentIrpStackLocation(irp
);
5370 irpStack
->DeviceObject
= deviceExtension
->DeviceObject
;
5373 // Construct the IRP stack for the lower level driver.
5376 irpStack
= IoGetNextIrpStackLocation(irp
);
5377 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
5378 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_OUT
;
5379 irpStack
->Parameters
.Scsi
.Srb
= srb
;
5381 IoSetCompletionRoutine(irp
,
5382 ToshibaProcessErrorCompletion
,
5388 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
5389 srb
->PathId
= deviceExtension
->PathId
;
5390 srb
->TargetId
= deviceExtension
->TargetId
;
5391 srb
->Lun
= deviceExtension
->Lun
;
5392 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
5393 srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
5394 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
5396 srb
->OriginalRequest
= irp
;
5397 srb
->SenseInfoBufferLength
= 0;
5400 // Set the transfer length.
5403 srb
->DataTransferLength
= length
;
5404 srb
->SrbFlags
= SRB_FLAGS_DATA_OUT
| SRB_FLAGS_DISABLE_AUTOSENSE
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
5408 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
5409 cdb
->MODE_SELECT
.PFBit
= 1;
5410 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)length
;
5413 // Copy the Mode page into the databuffer.
5416 RtlCopyMemory(srb
->DataBuffer
, &cdData
->u1
.Header
, length
);
5419 // Set the density code.
5422 ((PERROR_RECOVERY_DATA
)srb
->DataBuffer
)->BlockDescriptor
.DensityCode
= 0x83;
5424 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
5431 IN PDEVICE_OBJECT DeviceObject
5436 Routine Description:
5438 This routine determines if the cd is currently playing music.
5442 DeviceObject - Device object to test.
5446 TRUE if the device is playing music.
5450 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
5452 IO_STATUS_BLOCK ioStatus
;
5455 PSUB_Q_CURRENT_POSITION currentBuffer
;
5457 if (!PLAY_ACTIVE(deviceExtension
)) {
5461 currentBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, sizeof(SUB_Q_CURRENT_POSITION
));
5463 if (currentBuffer
== NULL
) {
5467 ((PCDROM_SUB_Q_DATA_FORMAT
) currentBuffer
)->Format
= IOCTL_CDROM_CURRENT_POSITION
;
5468 ((PCDROM_SUB_Q_DATA_FORMAT
) currentBuffer
)->Track
= 0;
5471 // Create notification event object to be used to signal the
5472 // request completion.
5475 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
5478 // Build the synchronous request to be sent to the port driver
5479 // to perform the request.
5482 irp
= IoBuildDeviceIoControlRequest(IOCTL_CDROM_READ_Q_CHANNEL
,
5483 deviceExtension
->DeviceObject
,
5485 sizeof(CDROM_SUB_Q_DATA_FORMAT
),
5487 sizeof(SUB_Q_CURRENT_POSITION
),
5493 ExFreePool(currentBuffer
);
5498 // Pass request to port driver and wait for request to complete.
5501 status
= IoCallDriver(deviceExtension
->DeviceObject
, irp
);
5503 if (status
== STATUS_PENDING
) {
5504 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
5505 status
= ioStatus
.Status
;
5508 if (!NT_SUCCESS(status
)) {
5509 ExFreePool(currentBuffer
);
5513 ExFreePool(currentBuffer
);
5515 return(PLAY_ACTIVE(deviceExtension
));
5519 IO_COMPLETION_ROUTINE CdRomMediaChangeCompletion
;
5522 CdRomMediaChangeCompletion(
5523 PDEVICE_OBJECT DeviceObject
,
5530 Routine Description:
5532 This routine handles the completion of the test unit ready irps
5533 used to determine if the media has changed. If the media has
5534 changed, this code signals the named event to wake up other
5535 system services that react to media change (aka AutoPlay).
5539 DeviceObject - the object for the completion
5540 Irp - the IRP being completed
5541 Context - the SRB from the IRP
5550 PSCSI_REQUEST_BLOCK srb
= (PSCSI_REQUEST_BLOCK
) Context
;
5551 PIO_STACK_LOCATION cdStack
= IoGetCurrentIrpStackLocation(Irp
);
5552 PIO_STACK_LOCATION irpNextStack
= IoGetNextIrpStackLocation(Irp
);
5553 PDEVICE_EXTENSION deviceExtension
;
5554 PDEVICE_EXTENSION physicalExtension
;
5555 PSENSE_DATA senseBuffer
;
5560 DeviceObject
= cdStack
->DeviceObject
;
5561 ASSERT(DeviceObject
);
5563 deviceExtension
= DeviceObject
->DeviceExtension
;
5564 physicalExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
5565 cddata
= (PCDROM_DATA
)(deviceExtension
+ 1);
5567 ASSERT(cddata
->MediaChangeIrp
== NULL
);
5570 // If the sense data field is valid, look for a media change.
5571 // otherwise this iteration of the polling will just assume nothing
5575 DebugPrint((3, "CdRomMediaChangeHandler: Completing Autorun Irp 0x%lx "
5577 Irp
, deviceExtension
->DeviceNumber
));
5579 if (srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) {
5580 if (srb
->SenseInfoBufferLength
>= FIELD_OFFSET(SENSE_DATA
, CommandSpecificInformation
)) {
5583 // See if this is a media change.
5586 senseBuffer
= srb
->SenseInfoBuffer
;
5587 if ((senseBuffer
->SenseKey
& 0x0f) == SCSI_SENSE_UNIT_ATTENTION
) {
5588 if (senseBuffer
->AdditionalSenseCode
== SCSI_ADSENSE_MEDIUM_CHANGED
) {
5590 DebugPrint((1, "CdRomMediaChangeCompletion: New media inserted "
5591 "into CdRom%d [irp = 0x%lx]\n",
5592 deviceExtension
->DeviceNumber
, Irp
));
5595 // Media change event occurred - signal the named event.
5598 KeSetEvent(deviceExtension
->MediaChangeEvent
,
5602 deviceExtension
->MediaChangeNoMedia
= FALSE
;
5606 if (DeviceObject
->Vpb
->Flags
& VPB_MOUNTED
) {
5609 // Must remember the media changed and force the
5610 // file system to verify on next access
5613 DeviceObject
->Flags
|= DO_VERIFY_VOLUME
;
5616 physicalExtension
->MediaChangeCount
++;
5618 } else if(((senseBuffer
->SenseKey
& 0x0f) == SCSI_SENSE_NOT_READY
)&&
5619 (senseBuffer
->AdditionalSenseCode
== SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
)&&
5620 (!deviceExtension
->MediaChangeNoMedia
)){
5623 // If there was no media in the device then signal the waiters if
5624 // we haven't already done so before.
5627 DebugPrint((1, "CdRomMediaChangeCompletion: No media in device"
5628 "CdRom%d [irp = 0x%lx]\n",
5629 deviceExtension
->DeviceNumber
, Irp
));
5631 KeSetEvent(deviceExtension
->MediaChangeEvent
,
5635 deviceExtension
->MediaChangeNoMedia
= TRUE
;
5639 } else if((srb
->SrbStatus
== SRB_STATUS_SUCCESS
)&&
5640 (deviceExtension
->MediaChangeNoMedia
)) {
5642 // We didn't have any media before and now the requests are succeeding
5643 // we probably missed the Media change somehow. Signal the change
5647 DebugPrint((1, "CdRomMediaChangeCompletion: Request completed normally"
5648 "for CdRom%d which was marked w/NoMedia [irp = 0x%lx]\n",
5649 deviceExtension
->DeviceNumber
, Irp
));
5651 KeSetEvent(deviceExtension
->MediaChangeEvent
,
5655 deviceExtension
->MediaChangeNoMedia
= FALSE
;
5659 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
5660 ScsiClassReleaseQueue(deviceExtension
->DeviceObject
);
5664 // Remember the IRP and SRB for use the next time.
5667 irpNextStack
->Parameters
.Scsi
.Srb
= srb
;
5668 cddata
->MediaChangeIrp
= Irp
;
5670 if (deviceExtension
->ClassError
) {
5676 // Throw away the status and retry values. Just give the error routine a chance
5677 // to do what it needs to.
5680 deviceExtension
->ClassError(DeviceObject
,
5686 IoStartNextPacket(DeviceObject
, FALSE
);
5688 return STATUS_MORE_PROCESSING_REQUIRED
;
5694 IN PDEVICE_OBJECT DeviceObject
,
5700 Routine Description:
5702 This routine handles the once per second timer provided by the
5703 Io subsystem. It is only used when the cdrom device itself is
5704 a candidate for autoplay support. It should never be called if
5705 the cdrom device is a changer device.
5709 DeviceObject - what to check.
5722 PLIST_ENTRY listEntry
;
5724 PIO_STACK_LOCATION irpStack
;
5725 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
5727 cddata
= (PCDROM_DATA
)(deviceExtension
+ 1);
5729 if (cddata
->MediaChange
) {
5730 if (cddata
->MediaChangeIrp
!= NULL
) {
5733 // Media change support is active and the IRP is waiting.
5734 // Decrement the timer.
5735 // There is no MP protection on the timer counter. This
5736 // code is the only code that will manipulate the timer
5737 // and only one instance of it should be running at any
5741 cddata
->MediaChangeCountDown
--;
5744 cddata
->MediaChangeIrpTimeInUse
= 0;
5745 cddata
->MediaChangeIrpLost
= FALSE
;
5748 if (!cddata
->MediaChangeCountDown
) {
5749 PSCSI_REQUEST_BLOCK srb
;
5750 PIO_STACK_LOCATION irpNextStack
;
5757 cddata
->MediaChangeCountDown
= MEDIA_CHANGE_DEFAULT_TIME
;
5760 // Prepare the IRP for the test unit ready
5763 irp
= cddata
->MediaChangeIrp
;
5764 cddata
->MediaChangeIrp
= NULL
;
5766 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
5767 irp
->IoStatus
.Information
= 0;
5769 irp
->UserBuffer
= NULL
;
5772 // If the irp is sent down when the volume needs to be
5773 // verified, CdRomUpdateGeometryCompletion won't complete
5774 // it since it's not associated with a thread. Marking
5775 // it to override the verify causes it always be sent
5776 // to the port driver
5779 irpStack
= IoGetCurrentIrpStackLocation(irp
);
5780 irpStack
->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
5782 irpNextStack
= IoGetNextIrpStackLocation(irp
);
5783 irpNextStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
5784 irpNextStack
->Parameters
.DeviceIoControl
.IoControlCode
=
5785 IOCTL_SCSI_EXECUTE_NONE
;
5788 // Prepare the SRB for execution.
5791 srb
= irpNextStack
->Parameters
.Scsi
.Srb
;
5792 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
5794 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
5795 srb
->PathId
= deviceExtension
->PathId
;
5796 srb
->TargetId
= deviceExtension
->TargetId
;
5797 srb
->Lun
= deviceExtension
->Lun
;
5798 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
5799 srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
|
5800 SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
5801 srb
->DataTransferLength
= 0;
5802 srb
->OriginalRequest
= irp
;
5804 RtlZeroMemory(srb
->SenseInfoBuffer
, SENSE_BUFFER_SIZE
);
5805 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
5807 cdb
= (PCDB
) &srb
->Cdb
[0];
5808 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_TEST_UNIT_READY
;
5809 cdb
->CDB6GENERIC
.LogicalUnitNumber
= srb
->Lun
;
5812 // Setup the IRP to perform a test unit ready.
5815 IoSetCompletionRoutine(irp
,
5816 CdRomMediaChangeCompletion
,
5823 // Issue the request.
5826 IoStartPacket(DeviceObject
, irp
, NULL
, NULL
);
5831 if(cddata
->MediaChangeIrpLost
== FALSE
) {
5832 if(cddata
->MediaChangeIrpTimeInUse
++ >
5833 MEDIA_CHANGE_TIMEOUT_TIME
) {
5835 DebugPrint((0, "CdRom%d: AutoPlay has lost it's irp and "
5836 "doesn't know where to find it. Leave it "
5837 "alone and it'll come home dragging it's "
5838 "stack behind it.\n",
5839 deviceExtension
->DeviceNumber
));
5840 cddata
->MediaChangeIrpLost
= TRUE
;
5849 // Process all generic timer IRPS in the timer list. As IRPs are pulled
5850 // off of the TimerIrpList they must be remembered in the first loop
5851 // if they are not sent to the lower driver. After all items have
5852 // been pulled off the list, it is possible to put the held IRPs back
5853 // into the TimerIrpList.
5857 if (IsListEmpty(&cddata
->TimerIrpList
)) {
5860 listEntry
= ExInterlockedRemoveHeadList(&cddata
->TimerIrpList
,
5861 &cddata
->TimerIrpSpinLock
);
5866 // There is something in the timer list. Pick up the IRP and
5867 // see if it is ready to be submitted.
5870 irp
= CONTAINING_RECORD(listEntry
, IRP
, Tail
.Overlay
.ListEntry
);
5871 irpStack
= IoGetCurrentIrpStackLocation(irp
);
5873 if (irpStack
->Parameters
.Others
.Argument3
) {
5877 // Decrement the countdown timer and put the IRP back in the list.
5880 count
= (ULONG_PTR
) irpStack
->Parameters
.Others
.Argument3
;
5882 irpStack
->Parameters
.Others
.Argument3
= (PVOID
) count
;
5884 ASSERT(irp
->AssociatedIrp
.MasterIrp
== NULL
);
5886 irp
->AssociatedIrp
.MasterIrp
= (PVOID
) heldIrpList
;
5893 // Submit this IRP to the lower driver. This IRP does not
5894 // need to be remembered here. It will be handled again when
5898 DebugPrint((1, "CdRomTickHandler: Reissuing request %lx (thread = %lx)\n", irp
, irp
->Tail
.Overlay
.Thread
));
5901 // feed this to the appropriate port driver
5904 IoCallDriver (deviceExtension
->PortDeviceObject
, irp
);
5909 // Pick up the next IRP from the timer list.
5912 listEntry
= ExInterlockedRemoveHeadList(&cddata
->TimerIrpList
,
5913 &cddata
->TimerIrpSpinLock
);
5917 // Move all held IRPs back onto the timer list.
5920 while (heldIrpList
) {
5923 // Save the single list pointer before queueing this IRP.
5926 nextIrp
= (PIRP
) heldIrpList
->AssociatedIrp
.MasterIrp
;
5927 heldIrpList
->AssociatedIrp
.MasterIrp
= NULL
;
5930 // Return the held IRP to the timer list.
5933 ExInterlockedInsertTailList(&cddata
->TimerIrpList
,
5934 &heldIrpList
->Tail
.Overlay
.ListEntry
,
5935 &cddata
->TimerIrpSpinLock
);
5938 // Continue processing the held IRPs
5941 heldIrpList
= nextIrp
;
5947 CdRomCheckRegistryForMediaChangeValue(
5948 IN PUNICODE_STRING RegistryPath
,
5949 IN ULONG DeviceNumber
5954 Routine Description:
5956 The user must specify that AutoPlay is to run on the platform
5957 by setting the registry value HKEY_LOCAL_MACHINE\System\CurrentControlSet\
5958 Services\Cdrom\Autorun:REG_DWORD:1.
5960 The user can override the global setting to enable or disable Autorun on a
5961 specific cdrom device by setting the key HKEY_LOCAL_MACHINE\System\
5962 CurrentControlSet\Services\Cdrom\Device<N>\Autorun:REG_DWORD to one or zero.
5963 (CURRENTLY UNIMPLEMENTED)
5965 If this registry value does not exist or contains the value zero then
5966 the timer to check for media change does not run.
5970 RegistryPath - pointer to the unicode string inside
5971 ...\CurrentControlSet\Services\Cdrom
5972 DeviceNumber - The number of the device object
5976 TRUE - Autorun is enabled.
5982 #define ITEMS_TO_QUERY 2 /* always 1 greater than what is searched */
5983 PRTL_QUERY_REGISTRY_TABLE parameters
= NULL
;
5991 ANSI_STRING paramNum
;
5993 UNICODE_STRING paramStr
;
5995 UNICODE_STRING paramSuffix
;
5996 UNICODE_STRING paramPath
;
5997 UNICODE_STRING paramDevPath
;
6000 // First append \Parameters to the passed in registry path
6003 RtlInitUnicodeString(¶mStr
, L
"\\Parameters");
6005 RtlInitUnicodeString(¶mPath
, NULL
);
6007 paramPath
.MaximumLength
= RegistryPath
->Length
+
6011 paramPath
.Buffer
= ExAllocatePool(PagedPool
, paramPath
.MaximumLength
);
6013 if(!paramPath
.Buffer
) {
6015 DebugPrint((1,"CdRomCheckRegAP: couldn't allocate paramPath\n"));
6020 RtlZeroMemory(paramPath
.Buffer
, paramPath
.MaximumLength
);
6021 RtlAppendUnicodeToString(¶mPath
, RegistryPath
->Buffer
);
6022 RtlAppendUnicodeToString(¶mPath
, paramStr
.Buffer
);
6024 DebugPrint((2, "CdRomCheckRegAP: paramPath [%d] = %ws\n",
6029 // build a counted ANSI string that contains
6030 // the suffix for the path
6033 sprintf(buf
, "\\Device%lu", DeviceNumber
);
6034 RtlInitAnsiString(¶mNum
, buf
);
6037 // Next convert this into a unicode string
6040 status
= RtlAnsiStringToUnicodeString(¶mSuffix
, ¶mNum
, TRUE
);
6042 if(!NT_SUCCESS(status
)) {
6043 DebugPrint((1,"CdRomCheckRegAP: couldn't convert paramNum to paramSuffix\n"));
6044 ExFreePool(paramPath
.Buffer
);
6048 RtlInitUnicodeString(¶mDevPath
, NULL
);
6051 // now build the device specific path
6054 paramDevPath
.MaximumLength
= paramPath
.Length
+
6055 paramSuffix
.Length
+
6057 paramDevPath
.Buffer
= ExAllocatePool(PagedPool
, paramDevPath
.MaximumLength
);
6059 if(!paramDevPath
.Buffer
) {
6060 RtlFreeUnicodeString(¶mSuffix
);
6061 ExFreePool(paramPath
.Buffer
);
6065 RtlZeroMemory(paramDevPath
.Buffer
, paramDevPath
.MaximumLength
);
6066 RtlAppendUnicodeToString(¶mDevPath
, paramPath
.Buffer
);
6067 RtlAppendUnicodeToString(¶mDevPath
, paramSuffix
.Buffer
);
6069 DebugPrint((2, "CdRomCheckRegAP: paramDevPath [%d] = %ws\n",
6073 parameters
= ExAllocatePool(NonPagedPool
,
6074 sizeof(RTL_QUERY_REGISTRY_TABLE
)*ITEMS_TO_QUERY
);
6079 // Check for the Autorun value.
6082 RtlZeroMemory(parameters
,
6083 (sizeof(RTL_QUERY_REGISTRY_TABLE
)*ITEMS_TO_QUERY
));
6085 parameters
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
6086 parameters
[0].Name
= L
"Autorun";
6087 parameters
[0].EntryContext
= &doRun
;
6088 parameters
[0].DefaultType
= REG_DWORD
;
6089 parameters
[0].DefaultData
= &zero
;
6090 parameters
[0].DefaultLength
= sizeof(ULONG
);
6092 status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
| RTL_REGISTRY_OPTIONAL
,
6093 RegistryPath
->Buffer
,
6098 DebugPrint((2, "CdRomCheckRegAP: cdrom/Autorun flag = %d\n", doRun
));
6100 RtlZeroMemory(parameters
,
6101 (sizeof(RTL_QUERY_REGISTRY_TABLE
)*ITEMS_TO_QUERY
));
6103 parameters
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
6104 parameters
[0].Name
= L
"Autorun";
6105 parameters
[0].EntryContext
= &tmp
;
6106 parameters
[0].DefaultType
= REG_DWORD
;
6107 parameters
[0].DefaultData
= &doRun
;
6108 parameters
[0].DefaultLength
= sizeof(ULONG
);
6110 status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
| RTL_REGISTRY_OPTIONAL
,
6116 DebugPrint((2, "CdRomCheckRegAP: cdrom/parameters/autorun flag = %d\n", tmp
));
6118 RtlZeroMemory(parameters
,
6119 (sizeof(RTL_QUERY_REGISTRY_TABLE
) * ITEMS_TO_QUERY
));
6121 parameters
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
6122 parameters
[0].Name
= L
"Autorun";
6123 parameters
[0].EntryContext
= &doRun
;
6124 parameters
[0].DefaultType
= REG_DWORD
;
6125 parameters
[0].DefaultData
= &tmp
;
6126 parameters
[0].DefaultLength
= sizeof(ULONG
);
6128 status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
| RTL_REGISTRY_OPTIONAL
,
6129 paramDevPath
.Buffer
,
6134 DebugPrint((1, "CdRomCheckRegAP: cdrom/parameters/device%d/autorun flag = %d\n", DeviceNumber
, doRun
));
6136 ExFreePool(parameters
);
6140 ExFreePool(paramPath
.Buffer
);
6141 ExFreePool(paramDevPath
.Buffer
);
6142 RtlFreeUnicodeString(¶mSuffix
);
6144 DebugPrint((1, "CdRomCheckRegAP: Autoplay for device %d is %s\n",
6146 (doRun
? "on" : "off")));
6159 IN PDEVICE_OBJECT DeviceObject
,
6166 Routine Description:
6168 This routine is called by DriverEntry to determine whether a Sanyo 3-CD
6169 changer device is present.
6173 DeviceObject - Supplies the device object for the 'real' device.
6179 TRUE - if an Atapi changer device is found.
6186 PCHAR inquiryBuffer
;
6187 IO_STATUS_BLOCK ioStatus
;
6189 PSCSI_ADAPTER_BUS_INFO adapterInfo
;
6191 PINQUIRYDATA inquiryData
;
6192 PSCSI_INQUIRY_DATA lunInfo
;
6194 inquiryBuffer
= ExAllocatePool(NonPagedPool
, 2048);
6195 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
6196 irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA
,
6209 status
= IoCallDriver(DeviceObject
, irp
);
6211 if (status
== STATUS_PENDING
) {
6212 KeWaitForSingleObject(&event
, Executive
, KernelMode
, FALSE
, NULL
);
6213 status
= ioStatus
.Status
;
6216 if (!NT_SUCCESS(status
)) {
6220 adapterInfo
= (PVOID
) inquiryBuffer
;
6222 for (scsiBus
=0; scsiBus
< (ULONG
)adapterInfo
->NumberOfBuses
; scsiBus
++) {
6225 // Get the SCSI bus scan data for this bus.
6228 lunInfo
= (PVOID
) (inquiryBuffer
+ adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
);
6232 if (lunInfo
->PathId
== PathId
&& lunInfo
->TargetId
== TargetId
) {
6234 inquiryData
= (PVOID
) lunInfo
->InquiryData
;
6236 if (RtlCompareMemory(inquiryData
->VendorId
, "TORiSAN CD-ROM CDR-C", 20) == 20) {
6237 ExFreePool(inquiryBuffer
);
6241 ExFreePool(inquiryBuffer
);
6245 if (!lunInfo
->NextInquiryDataOffset
) {
6249 lunInfo
= (PVOID
) (inquiryBuffer
+ lunInfo
->NextInquiryDataOffset
);
6253 ExFreePool(inquiryBuffer
);
6259 IsThisAnAtapiChanger(
6260 IN PDEVICE_OBJECT DeviceObject
,
6261 OUT PULONG DiscsPresent
6266 Routine Description:
6268 This routine is called by DriverEntry to determine whether an Atapi
6269 changer device is present.
6273 DeviceObject - Supplies the device object for the 'real' device.
6275 DiscsPresent - Supplies a pointer to the number of Discs supported by the changer.
6279 TRUE - if an Atapi changer device is found.
6284 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
6285 PMECHANICAL_STATUS_INFORMATION_HEADER mechanicalStatusBuffer
;
6287 SCSI_REQUEST_BLOCK srb
;
6288 PCDB cdb
= (PCDB
) &srb
.Cdb
[0];
6289 BOOLEAN retVal
= FALSE
;
6294 // Some devices can't handle 12 byte CDB's gracefully
6297 if(deviceExtension
->DeviceFlags
& DEV_NO_12BYTE_CDB
) {
6304 // Build and issue the mechanical status command.
6307 mechanicalStatusBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
6308 sizeof(MECHANICAL_STATUS_INFORMATION_HEADER
));
6310 if (!mechanicalStatusBuffer
) {
6315 // Build and send the Mechanism status CDB.
6318 RtlZeroMemory(&srb
, sizeof(srb
));
6321 srb
.TimeOutValue
= 20;
6323 cdb
->MECH_STATUS
.OperationCode
= SCSIOP_MECHANISM_STATUS
;
6324 cdb
->MECH_STATUS
.AllocationLength
[1] = sizeof(MECHANICAL_STATUS_INFORMATION_HEADER
);
6326 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
6328 mechanicalStatusBuffer
,
6329 sizeof(MECHANICAL_STATUS_INFORMATION_HEADER
),
6333 if (status
== STATUS_SUCCESS
) {
6336 // Indicate number of slots available
6339 *DiscsPresent
= mechanicalStatusBuffer
->NumberAvailableSlots
;
6340 if (*DiscsPresent
> 1) {
6345 // If only one disc, no need for this driver.
6353 // Device doesn't support this command.
6359 ExFreePool(mechanicalStatusBuffer
);
6367 IsThisAMultiLunDevice(
6368 IN PDEVICE_OBJECT DeviceObject
,
6369 IN PDEVICE_OBJECT PortDeviceObject
6373 Routine Description:
6375 This routine is called to determine whether a multi-lun
6380 DeviceObject - Supplies the device object for the 'real' device.
6384 TRUE - if a Multi-lun device is found.
6389 PSCSI_INQUIRY_DATA lunInfo
;
6390 PSCSI_ADAPTER_BUS_INFO adapterInfo
;
6391 PDEVICE_EXTENSION deviceExtension
= (PDEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
6392 PINQUIRYDATA inquiryData
;
6397 status
= ScsiClassGetInquiryData(PortDeviceObject
, (PSCSI_ADAPTER_BUS_INFO
*) &buffer
);
6399 if (!NT_SUCCESS(status
)) {
6400 DebugPrint((1,"IsThisAMultiLunDevice: ScsiClassGetInquiryData failed\n"));
6404 adapterInfo
= (PVOID
) buffer
;
6407 // For each SCSI bus this adapter supports ...
6410 for (scsiBus
=0; scsiBus
< adapterInfo
->NumberOfBuses
; scsiBus
++) {
6413 // Get the SCSI bus scan data for this bus.
6416 lunInfo
= (PVOID
) (buffer
+ adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
);
6418 while (adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
) {
6420 inquiryData
= (PVOID
)lunInfo
->InquiryData
;
6422 if ((lunInfo
->PathId
== deviceExtension
->PathId
) &&
6423 (lunInfo
->TargetId
== deviceExtension
->TargetId
) &&
6424 (inquiryData
->DeviceType
== READ_ONLY_DIRECT_ACCESS_DEVICE
)) {
6426 DebugPrint((1,"IsThisAMultiLunDevice: Vendor string is %.24s\n",
6427 inquiryData
->VendorId
));
6430 // If this device has more than one cdrom-type lun then we
6431 // won't support autoplay on it
6441 // Get next LunInfo.
6444 if (lunInfo
->NextInquiryDataOffset
== 0) {
6448 lunInfo
= (PVOID
) (buffer
+ lunInfo
->NextInquiryDataOffset
);
6457 IO_COMPLETION_ROUTINE CdRomUpdateGeometryCompletion
;
6460 CdRomUpdateGeometryCompletion(
6461 PDEVICE_OBJECT DeviceObject
,
6468 Routine Description:
6470 This routine andles the completion of the test unit ready irps
6471 used to determine if the media has changed. If the media has
6472 changed, this code signals the named event to wake up other
6473 system services that react to media change (aka AutoPlay).
6477 DeviceObject - the object for the completion
6478 Irp - the IRP being completed
6479 Context - the SRB from the IRP
6488 PSCSI_REQUEST_BLOCK srb
= (PSCSI_REQUEST_BLOCK
) Context
;
6489 PREAD_CAPACITY_DATA readCapacityBuffer
;
6490 PDEVICE_EXTENSION deviceExtension
;
6491 PIO_STACK_LOCATION irpStack
;
6494 ULONG_PTR retryCount
;
6500 // Get items saved in the private IRP stack location.
6503 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
6504 retryCount
= (ULONG_PTR
) irpStack
->Parameters
.Others
.Argument1
;
6505 originalIrp
= (PIRP
) irpStack
->Parameters
.Others
.Argument2
;
6507 if (!DeviceObject
) {
6508 DeviceObject
= irpStack
->DeviceObject
;
6510 ASSERT(DeviceObject
);
6512 deviceExtension
= DeviceObject
->DeviceExtension
;
6513 cddata
= (PCDROM_DATA
) (deviceExtension
+ 1);
6514 readCapacityBuffer
= srb
->DataBuffer
;
6516 if ((NT_SUCCESS(Irp
->IoStatus
.Status
)) && (SRB_STATUS(srb
->SrbStatus
) == SRB_STATUS_SUCCESS
)) {
6520 DebugPrint((2, "CdRomUpdateCapacityCompletion: [%lx] successful completion of buddy-irp %lx\n", originalIrp
, Irp
));
6522 // Copy sector size from read capacity buffer to device extension
6523 // in reverse byte order.
6526 from
= (PFOUR_BYTE
) &readCapacityBuffer
->BytesPerBlock
;
6527 to
= (PFOUR_BYTE
) &deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
;
6528 to
->Byte0
= from
->Byte3
;
6529 to
->Byte1
= from
->Byte2
;
6530 to
->Byte2
= from
->Byte1
;
6531 to
->Byte3
= from
->Byte0
;
6534 // Using the new BytesPerBlock, calculate and store the SectorShift.
6537 WHICH_BIT(deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
, deviceExtension
->SectorShift
);
6540 // Copy last sector in reverse byte order.
6543 from
= (PFOUR_BYTE
) &readCapacityBuffer
->LogicalBlockAddress
;
6544 to
= (PFOUR_BYTE
) &lastSector
;
6545 to
->Byte0
= from
->Byte3
;
6546 to
->Byte1
= from
->Byte2
;
6547 to
->Byte2
= from
->Byte1
;
6548 to
->Byte3
= from
->Byte0
;
6549 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(lastSector
+ 1);
6552 // Calculate number of cylinders.
6555 deviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
= (LONGLONG
)((lastSector
+ 1)/(32 * 64));
6556 deviceExtension
->PartitionLength
.QuadPart
=
6557 (deviceExtension
->PartitionLength
.QuadPart
<< deviceExtension
->SectorShift
);
6558 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= RemovableMedia
;
6561 // Assume sectors per track are 32;
6564 deviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
= 32;
6567 // Assume tracks per cylinder (number of heads) is 64.
6570 deviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
= 64;
6574 DebugPrint((1, "CdRomUpdateCapacityCompletion: [%lx] unsuccessful completion of buddy-irp %lx (status - %lx)\n", originalIrp
, Irp
, Irp
->IoStatus
.Status
));
6576 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
6577 ScsiClassReleaseQueue(DeviceObject
);
6580 retry
= ScsiClassInterpretSenseInfo(DeviceObject
,
6591 DebugPrint((1, "CdRomUpdateCapacityCompletion: [%lx] Retrying request %lx .. thread is %lx\n", originalIrp
, Irp
, Irp
->Tail
.Overlay
.Thread
));
6593 // set up a one shot timer to get this process started over
6596 irpStack
->Parameters
.Others
.Argument1
= (PVOID
) retryCount
;
6597 irpStack
->Parameters
.Others
.Argument2
= (PVOID
) originalIrp
;
6598 irpStack
->Parameters
.Others
.Argument3
= (PVOID
) 2;
6601 // Setup the IRP to be submitted again in the timer routine.
6604 irpStack
= IoGetNextIrpStackLocation(Irp
);
6605 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
6606 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
6607 irpStack
->Parameters
.Scsi
.Srb
= srb
;
6608 IoSetCompletionRoutine(Irp
,
6609 CdRomUpdateGeometryCompletion
,
6616 // Set up the SRB for read capacity.
6619 srb
->CdbLength
= 10;
6620 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
6621 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
6623 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
6624 srb
->PathId
= deviceExtension
->PathId
;
6625 srb
->TargetId
= deviceExtension
->TargetId
;
6626 srb
->Lun
= deviceExtension
->Lun
;
6627 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
6628 srb
->SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
6629 srb
->DataTransferLength
= sizeof(READ_CAPACITY_DATA
);
6635 cdb
= (PCDB
) &srb
->Cdb
[0];
6636 cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
6637 cdb
->CDB10
.LogicalUnitNumber
= deviceExtension
->Lun
;
6640 // Requests queued onto this list will be sent to the
6641 // lower level driver during CdRomTickHandler
6644 ExInterlockedInsertHeadList(&cddata
->TimerIrpList
,
6645 &Irp
->Tail
.Overlay
.ListEntry
,
6646 &cddata
->TimerIrpSpinLock
);
6648 return STATUS_MORE_PROCESSING_REQUIRED
;
6652 // This has been bounced for a number of times. Error the
6653 // original request.
6656 originalIrp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
6657 RtlZeroMemory(deviceExtension
->DiskGeometry
, sizeof(DISK_GEOMETRY_EX
));
6658 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= 2048;
6659 deviceExtension
->SectorShift
= 11;
6660 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(0x7fffffff);
6661 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= RemovableMedia
;
6666 // Set up reasonable defaults
6669 RtlZeroMemory(deviceExtension
->DiskGeometry
, sizeof(DISK_GEOMETRY_EX
));
6670 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= 2048;
6671 deviceExtension
->SectorShift
= 11;
6672 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(0x7fffffff);
6673 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= RemovableMedia
;
6678 // Free resources held.
6681 ExFreePool(srb
->SenseInfoBuffer
);
6682 ExFreePool(srb
->DataBuffer
);
6684 if (Irp
->MdlAddress
) {
6685 IoFreeMdl(Irp
->MdlAddress
);
6688 if (originalIrp
->Tail
.Overlay
.Thread
) {
6690 DebugPrint((2, "CdRomUpdateCapacityCompletion: [%lx] completing original IRP\n", originalIrp
));
6691 IoCompleteRequest(originalIrp
, IO_DISK_INCREMENT
);
6694 DebugPrint((1, "CdRomUpdateCapacityCompletion: [%lx] original irp has "
6701 // It's now safe to either start the next request or let the waiting ioctl
6702 // request continue along it's merry way
6705 IoStartNextPacket(DeviceObject
, FALSE
);
6707 return STATUS_MORE_PROCESSING_REQUIRED
;
6712 CdRomUpdateCapacity(
6713 IN PDEVICE_EXTENSION DeviceExtension
,
6714 IN PIRP IrpToComplete
,
6715 IN OPTIONAL PKEVENT IoctlEvent
6720 Routine Description:
6722 This routine updates the capacity of the disk as recorded in the device extension.
6723 It also completes the IRP given with STATUS_VERIFY_REQUIRED. This routine is called
6724 when a media change has occurred and it is necessary to determine the capacity of the
6725 new media prior to the next access.
6729 DeviceExtension - the device to update
6730 IrpToComplete - the request that needs to be completed when done.
6741 PSCSI_REQUEST_BLOCK srb
;
6742 PREAD_CAPACITY_DATA capacityBuffer
;
6743 PIO_STACK_LOCATION irpStack
;
6747 irp
= IoAllocateIrp((CCHAR
)(DeviceExtension
->DeviceObject
->StackSize
+1),
6752 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
6754 capacityBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
6755 sizeof(READ_CAPACITY_DATA
));
6757 if (capacityBuffer
) {
6760 senseBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
6764 irp
->MdlAddress
= IoAllocateMdl(capacityBuffer
,
6765 sizeof(READ_CAPACITY_DATA
),
6770 if (irp
->MdlAddress
) {
6773 // Have all resources. Set up the IRP to send for the capacity.
6776 IoSetNextIrpStackLocation(irp
);
6777 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
6778 irp
->IoStatus
.Information
= 0;
6780 irp
->UserBuffer
= NULL
;
6783 // Save the device object and retry count in a private stack location.
6786 irpStack
= IoGetCurrentIrpStackLocation(irp
);
6787 irpStack
->DeviceObject
= DeviceExtension
->DeviceObject
;
6788 irpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
6789 irpStack
->Parameters
.Others
.Argument2
= (PVOID
) IrpToComplete
;
6792 // Construct the IRP stack for the lower level driver.
6795 irpStack
= IoGetNextIrpStackLocation(irp
);
6796 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
6797 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
6798 irpStack
->Parameters
.Scsi
.Srb
= srb
;
6799 IoSetCompletionRoutine(irp
,
6800 CdRomUpdateGeometryCompletion
,
6809 MmBuildMdlForNonPagedPool(irp
->MdlAddress
);
6813 // Set up the SRB for read capacity.
6816 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
6817 RtlZeroMemory(senseBuffer
, SENSE_BUFFER_SIZE
);
6818 srb
->CdbLength
= 10;
6819 srb
->TimeOutValue
= DeviceExtension
->TimeOutValue
;
6820 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
6822 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
6823 srb
->PathId
= DeviceExtension
->PathId
;
6824 srb
->TargetId
= DeviceExtension
->TargetId
;
6825 srb
->Lun
= DeviceExtension
->Lun
;
6826 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
6827 srb
->SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
6828 srb
->DataBuffer
= capacityBuffer
;
6829 srb
->DataTransferLength
= sizeof(READ_CAPACITY_DATA
);
6830 srb
->OriginalRequest
= irp
;
6831 srb
->SenseInfoBuffer
= senseBuffer
;
6832 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
6838 cdb
= (PCDB
) &srb
->Cdb
[0];
6839 cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
6840 cdb
->CDB10
.LogicalUnitNumber
= DeviceExtension
->Lun
;
6843 // Set the return value in the IRP that will be completed
6844 // upon completion of the read capacity.
6847 IrpToComplete
->IoStatus
.Status
= STATUS_VERIFY_REQUIRED
;
6848 IoMarkIrpPending(IrpToComplete
);
6850 status
= IoCallDriver(DeviceExtension
->PortDeviceObject
, irp
);
6853 // status is not checked because the completion routine for this
6854 // IRP will always get called and it will free the resources.
6857 return STATUS_PENDING
;
6860 ExFreePool(senseBuffer
);
6861 ExFreePool(capacityBuffer
);
6866 ExFreePool(capacityBuffer
);
6879 return STATUS_INSUFFICIENT_RESOURCES
;
6884 CdRomClassIoctlCompletion(
6885 IN PDEVICE_OBJECT DeviceObject
,
6892 Routine Description:
6894 This routine signals the event used by CdRomDeviceControl to synchronize
6895 class driver (and lower level driver) ioctls with cdrom's startio routine.
6896 The irp completion is short-circuited so that CdRomDeviceControl can
6897 reissue it once it wakes up.
6901 DeviceObject - the device object
6902 Irp - the request we are synchronizing
6903 Context - a PKEVENT that we need to signal
6912 PKEVENT syncEvent
= (PKEVENT
) Context
;
6914 DebugPrint((2, "CdRomClassIoctlCompletion: setting event for irp %#08lx\n",
6918 KeSetEvent(syncEvent
, IO_DISK_INCREMENT
, FALSE
);
6920 return STATUS_MORE_PROCESSING_REQUIRED
;