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 #include <include/class2.h>
20 #define CDB12GENERIC_LENGTH 12
22 typedef struct _XA_CONTEXT
{
25 // Pointer to the device object.
28 PDEVICE_OBJECT DeviceObject
;
31 // Pointer to the original request when
32 // a mode select must be sent.
38 // Pointer to the mode select srb.
41 PSCSI_REQUEST_BLOCK Srb
;
42 } XA_CONTEXT
, *PXA_CONTEXT
;
44 typedef struct _ERROR_RECOVERY_DATA
{
45 MODE_PARAMETER_HEADER Header
;
46 MODE_PARAMETER_BLOCK BlockDescriptor
;
47 MODE_READ_RECOVERY_PAGE ReadRecoveryPage
;
48 } ERROR_RECOVERY_DATA
, *PERROR_RECOVERY_DATA
;
50 typedef struct _ERROR_RECOVERY_DATA10
{
51 MODE_PARAMETER_HEADER10 Header10
;
52 MODE_PARAMETER_BLOCK BlockDescriptor10
;
53 MODE_READ_RECOVERY_PAGE ReadRecoveryPage10
;
54 } ERROR_RECOVERY_DATA10
, *PERROR_RECOVERY_DATA10
;
57 // CdRom specific addition to device extension.
60 typedef struct _CDROM_DATA
{
63 // Indicates whether an audio play operation
64 // is currently being performed.
70 // Indicates whether the blocksize used for user data
77 // Indicates whether 6 or 10 byte mode sense/select
84 // Storage for the error recovery page. This is used
85 // as an easy method to switch block sizes.
89 ERROR_RECOVERY_DATA u1
;
90 ERROR_RECOVERY_DATA10 u2
;
95 // Pointer to the original irp for the raw read.
101 // Used to protect accesses to the RawAccess flag.
104 KSPIN_LOCK FormSpinLock
;
107 // Even if media change support is requested, there are some devices
108 // that are not supported. This flag will indicate that such a device
109 // is present when it is FALSE.
112 BOOLEAN MediaChangeSupported
;
115 // The media change event is being supported. The media change timer
116 // should be running whenever this is true.
122 // The timer value to support media change events. This is a countdown
123 // value used to determine when to poll the device for a media change.
124 // The max value for the timer is 255 seconds.
127 UCHAR MediaChangeCountDown
;
131 // Second timer to keep track of how long the media change IRP has been
132 // in use. If this value exceeds the timeout (#defined) then we should
133 // print out a message to the user and set the MediaChangeIrpLost flag
136 SHORT MediaChangeIrpTimeInUse
;
139 // Set by CdRomTickHandler when we determine that the media change irp has
143 BOOLEAN MediaChangeIrpLost
;
146 UCHAR PadReserve
; // use this for new flags.
149 // An IRP is allocated and kept for the duration that media change
150 // detection is in effect. If this is NULL and MediaChange is TRUE,
151 // the detection is in progress. This should always be NULL when
152 // MediaChange is FALSE.
158 // The timer work list is a collection of IRPS that are prepared for
159 // submission, but need to allow some time to pass before they are
163 LIST_ENTRY TimerIrpList
;
164 KSPIN_LOCK TimerIrpSpinLock
;
166 } CDROM_DATA
, *PCDROM_DATA
;
168 #define DEVICE_EXTENSION_SIZE sizeof(DEVICE_EXTENSION) + sizeof(CDROM_DATA)
169 #define SCSI_CDROM_TIMEOUT 10
170 #define SCSI_CHANGER_BONUS_TIMEOUT 10
171 #define HITACHI_MODE_DATA_SIZE 12
172 #define MODE_DATA_SIZE 64
173 #define RAW_SECTOR_SIZE 2352
174 #define COOKED_SECTOR_SIZE 2048
175 #define MEDIA_CHANGE_DEFAULT_TIME 4
176 #define CDROM_SRB_LIST_SIZE 4
182 // Used to detect the loss of the autorun irp. The driver prints out a message
183 // (debug level 0) if this timeout ever occurs
185 #define MEDIA_CHANGE_TIMEOUT_TIME 300
189 #define PLAY_ACTIVE(DeviceExtension) (((PCDROM_DATA)(DeviceExtension + 1))->PlayActive)
191 #define MSF_TO_LBA(Minutes,Seconds,Frames) \
192 (ULONG)((60 * 75 * (Minutes)) + (75 * (Seconds)) + ((Frames) - 150))
194 #define LBA_TO_MSF(Lba,Minutes,Seconds,Frames) \
196 (Minutes) = (UCHAR)(Lba / (60 * 75)); \
197 (Seconds) = (UCHAR)((Lba % (60 * 75)) / 75); \
198 (Frames) = (UCHAR)((Lba % (60 * 75)) % 75); \
201 #define DEC_TO_BCD(x) (((x / 10) << 4) + (x % 10))
204 // Define flags for XA, CDDA, and Mode Select/Sense
207 #define XA_USE_6_BYTE 0x01
208 #define XA_USE_10_BYTE 0x02
209 #define XA_USE_READ_CD 0x04
210 #define XA_NOT_SUPPORTED 0x08
212 #define PLEXTOR_CDDA 0x10
213 #define NEC_CDDA 0x20
216 // Sector types for READ_CD
220 #define CD_DA_SECTOR 1
221 #define YELLOW_MODE1_SECTOR 2
222 #define YELLOW_MODE2_SECTOR 3
223 #define FORM2_MODE1_SECTOR 4
224 #define FORM2_MODE2_SECTOR 5
228 #ifdef ExAllocatePool
229 #undef ExAllocatePool
231 #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'CscS')
237 IN PDRIVER_OBJECT DriverObject
,
238 IN PUNICODE_STRING RegistryPath
243 ScsiCdRomFindDevices(
244 IN PDRIVER_OBJECT DriverObject
,
245 IN PUNICODE_STRING RegistryPath
,
246 IN PCLASS_INIT_DATA InitializationData
,
247 IN PDEVICE_OBJECT PortDeviceObject
,
254 IN PDEVICE_OBJECT DeviceObject
,
260 ScsiCdRomReadVerification(
261 IN PDEVICE_OBJECT DeviceObject
,
268 IN PDEVICE_OBJECT DeviceObject
,
270 IN PIRP OriginalRequest
276 IN PDEVICE_OBJECT DeviceObject
,
280 IO_COMPLETION_ROUTINE CdRomDeviceControlCompletion
;
283 CdRomDeviceControlCompletion(
284 IN PDEVICE_OBJECT DeviceObject
,
289 IO_COMPLETION_ROUTINE CdRomSetVolumeIntermediateCompletion
;
292 CdRomSetVolumeIntermediateCompletion(
293 IN PDEVICE_OBJECT DeviceObject
,
298 IO_COMPLETION_ROUTINE CdRomSwitchModeCompletion
;
301 CdRomSwitchModeCompletion(
302 IN PDEVICE_OBJECT DeviceObject
,
307 IO_COMPLETION_ROUTINE CdRomXACompletion
;
311 IN PDEVICE_OBJECT DeviceObject
,
316 IO_COMPLETION_ROUTINE CdRomClassIoctlCompletion
;
319 CdRomClassIoctlCompletion(
320 IN PDEVICE_OBJECT DeviceObject
,
328 IN PDEVICE_OBJECT DeviceObject
,
335 IN PDEVICE_OBJECT DeviceObject
,
341 CdRomCheckRegistryForMediaChangeValue(
342 IN PUNICODE_STRING RegistryPath
,
343 IN ULONG DeviceNumber
349 IN PDEVICE_EXTENSION DeviceExtension
,
350 IN PIRP IrpToComplete
,
351 IN OPTIONAL PKEVENT IoctlEvent
356 CreateCdRomDeviceObject(
357 IN PDRIVER_OBJECT DriverObject
,
358 IN PDEVICE_OBJECT PortDeviceObject
,
360 IN PULONG DeviceCount
,
361 PIO_SCSI_CAPABILITIES PortCapabilities
,
362 IN PSCSI_INQUIRY_DATA LunInfo
,
363 IN PCLASS_INIT_DATA InitializationData
,
364 IN PUNICODE_STRING RegistryPath
370 PDEVICE_OBJECT DeviceObject
,
371 PINQUIRYDATA InquiryData
,
372 PIO_SCSI_CAPABILITIES PortCapabilities
378 IN PDEVICE_OBJECT DeviceObject
384 PDEVICE_OBJECT DeviceObject
,
385 PSCSI_REQUEST_BLOCK Srb
,
390 IO_COMPLETION_ROUTINE ToshibaProcessErrorCompletion
;
394 PDEVICE_OBJECT DeviceObject
,
395 PSCSI_REQUEST_BLOCK Srb
,
402 IsThisAnAtapiChanger(
403 IN PDEVICE_OBJECT DeviceObject
,
404 OUT PULONG DiscsPresent
410 IN PDEVICE_OBJECT DeviceObject
,
417 IsThisAMultiLunDevice(
418 IN PDEVICE_OBJECT DeviceObject
,
419 IN PDEVICE_OBJECT PortDeviceObject
424 CdRomCreateNamedEvent(
425 IN PDEVICE_EXTENSION DeviceExtension
,
426 IN ULONG DeviceNumber
433 IN UNICODE_STRING ScsiUnicodeString
[],
434 OUT PUCHAR IntermediateController
439 #pragma alloc_text(PAGE, DriverEntry)
440 #pragma alloc_text(PAGE, ScsiCdRomFindDevices)
441 #pragma alloc_text(PAGE, CreateCdRomDeviceObject)
442 #pragma alloc_text(PAGE, ScanForSpecial)
443 //#pragma alloc_text(PAGE, CdRomDeviceControl)
444 #pragma alloc_text(PAGE, HitachProcessError)
445 #pragma alloc_text(PAGE, CdRomIsPlayActive)
446 #pragma alloc_text(PAGE, ScsiCdRomReadVerification)
447 #pragma alloc_text(INIT, CdRomCheckRegistryForMediaChangeValue)
448 #pragma alloc_text(INIT, IsThisAnAtapiChanger)
449 #pragma alloc_text(INIT, IsThisASanyo)
450 #pragma alloc_text(INIT, IsThisAMultiLunDevice)
451 #pragma alloc_text(INIT, CdRomCreateNamedEvent)
453 #pragma alloc_text(PAGE, FindScsiAdapter)
462 IN PDRIVER_OBJECT DriverObject
,
463 IN PUNICODE_STRING RegistryPath
470 This routine initializes the cdrom class driver.
474 DriverObject - Pointer to driver object created by system.
476 RegistryPath - Pointer to the name of the services node for this driver.
480 The function value is the final status from the initialization operation.
485 CLASS_INIT_DATA InitializationData
;
488 return STATUS_NO_SUCH_DEVICE
;
495 RtlZeroMemory (&InitializationData
, sizeof(CLASS_INIT_DATA
));
501 InitializationData
.InitializationDataSize
= sizeof(CLASS_INIT_DATA
);
502 InitializationData
.DeviceExtensionSize
= DEVICE_EXTENSION_SIZE
;
504 InitializationData
.DeviceType
= FILE_DEVICE_CD_ROM
;
505 InitializationData
.DeviceCharacteristics
= FILE_REMOVABLE_MEDIA
| FILE_READ_ONLY_DEVICE
;
511 InitializationData
.ClassReadWriteVerification
= ScsiCdRomReadVerification
;
512 InitializationData
.ClassDeviceControl
= CdRomDeviceControl
;
513 InitializationData
.ClassFindDevices
= ScsiCdRomFindDevices
;
514 InitializationData
.ClassShutdownFlush
= NULL
;
515 InitializationData
.ClassCreateClose
= NULL
;
516 InitializationData
.ClassStartIo
= ScsiCdRomStartIo
;
519 // Call the class init routine
522 return ScsiClassInitialize( DriverObject
, RegistryPath
, &InitializationData
);
524 } // end DriverEntry()
528 ScsiCdRomFindDevices(
529 IN PDRIVER_OBJECT DriverObject
,
530 IN PUNICODE_STRING RegistryPath
,
531 IN PCLASS_INIT_DATA InitializationData
,
532 IN PDEVICE_OBJECT PortDeviceObject
,
540 Connect to SCSI port driver. Get adapter capabilities and
541 SCSI bus configuration information. Search inquiry data
542 for CDROM devices to process.
546 DriverObject - CDROM class driver object.
547 PortDeviceObject - SCSI port driver device object.
548 PortNumber - The system ordinal for this scsi adapter.
552 TRUE if CDROM device present on this SCSI adapter.
557 PIO_SCSI_CAPABILITIES portCapabilities
;
560 PSCSI_INQUIRY_DATA lunInfo
;
561 PSCSI_ADAPTER_BUS_INFO adapterInfo
;
562 PINQUIRYDATA inquiryData
;
565 BOOLEAN foundDevice
= FALSE
;
568 // Call port driver to get adapter capabilities.
571 status
= ScsiClassGetCapabilities(PortDeviceObject
, &portCapabilities
);
573 if (!NT_SUCCESS(status
)) {
574 DebugPrint((1,"FindScsiDevices: ScsiClassGetCapabilities failed\n"));
579 // Call port driver to get inquiry information to find cdroms.
582 status
= ScsiClassGetInquiryData(PortDeviceObject
, (PSCSI_ADAPTER_BUS_INFO
*) &buffer
);
584 if (!NT_SUCCESS(status
)) {
585 DebugPrint((1,"FindScsiDevices: ScsiClassGetInquiryData failed\n"));
590 // Get the address of the count of the number of cdroms already initialized.
593 cdRomCount
= &IoGetConfigurationInformation()->CdRomCount
;
594 adapterInfo
= (PVOID
) buffer
;
597 // For each SCSI bus this adapter supports ...
600 for (scsiBus
=0; scsiBus
< adapterInfo
->NumberOfBuses
; scsiBus
++) {
603 // Get the SCSI bus scan data for this bus.
606 lunInfo
= (PVOID
) (buffer
+ adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
);
609 // Search list for unclaimed disk devices.
612 while (adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
) {
614 inquiryData
= (PVOID
)lunInfo
->InquiryData
;
616 if ((inquiryData
->DeviceType
== READ_ONLY_DIRECT_ACCESS_DEVICE
) &&
617 (inquiryData
->DeviceTypeQualifier
== 0) &&
618 (!lunInfo
->DeviceClaimed
)) {
620 DebugPrint((1,"FindScsiDevices: Vendor string is %.24s\n",
621 inquiryData
->VendorId
));
624 // Create device objects for cdrom
627 status
= CreateCdRomDeviceObject(DriverObject
,
636 if (NT_SUCCESS(status
)) {
639 // Increment system cdrom device count.
645 // Indicate that a cdrom device was found.
656 if (lunInfo
->NextInquiryDataOffset
== 0) {
660 lunInfo
= (PVOID
) (buffer
+ lunInfo
->NextInquiryDataOffset
);
669 } // end FindScsiCdRoms()
673 CdRomCreateNamedEvent(
674 IN PDEVICE_EXTENSION DeviceExtension
,
675 IN ULONG DeviceNumber
682 Create the named synchronization event for notification of media change
683 events to the system. The event is reset before this function returns.
687 DeviceExtension - the device extension pointer for storage of the event pointer.
696 UNICODE_STRING unicodeString
;
697 OBJECT_ATTRIBUTES objectAttributes
;
698 CCHAR eventNameBuffer
[MAXIMUM_FILENAME_LENGTH
];
699 STRING eventNameString
;
704 sprintf(eventNameBuffer
,"\\Device\\MediaChangeEvent%ld",
707 RtlInitString(&eventNameString
,
710 status
= RtlAnsiStringToUnicodeString(&unicodeString
,
714 if (!NT_SUCCESS(status
)) {
718 InitializeObjectAttributes(&objectAttributes
,
720 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
724 DeviceExtension
->MediaChangeEvent
= IoCreateSynchronizationEvent(&unicodeString
,
726 DeviceExtension
->MediaChangeEventHandle
= handle
;
728 KeClearEvent(DeviceExtension
->MediaChangeEvent
);
730 RtlFreeUnicodeString(&unicodeString
);
735 CreateCdRomDeviceObject(
736 IN PDRIVER_OBJECT DriverObject
,
737 IN PDEVICE_OBJECT PortDeviceObject
,
739 IN PULONG DeviceCount
,
740 IN PIO_SCSI_CAPABILITIES PortCapabilities
,
741 IN PSCSI_INQUIRY_DATA LunInfo
,
742 IN PCLASS_INIT_DATA InitializationData
,
743 IN PUNICODE_STRING RegistryPath
750 This routine creates an object for the device and then calls the
751 SCSI port driver for media capacity and sector size.
755 DriverObject - Pointer to driver object created by system.
756 PortDeviceObject - to connect to SCSI port driver.
757 DeviceCount - Number of previously installed CDROMs.
758 PortCapabilities - Pointer to structure returned by SCSI port
759 driver describing adapter capabilites (and limitations).
760 LunInfo - Pointer to configuration information for this device.
768 CHAR ntNameBuffer
[64];
770 BOOLEAN changerDevice
;
771 SCSI_REQUEST_BLOCK srb
;
775 PVOID senseData
= NULL
;
776 PDEVICE_OBJECT deviceObject
= NULL
;
777 PDEVICE_EXTENSION deviceExtension
= NULL
;
782 BOOLEAN srbListInitialized
= FALSE
;
785 // Claim the device. Note that any errors after this
786 // will goto the generic handler, where the device will
790 status
= ScsiClassClaimDevice(PortDeviceObject
,
795 if (!NT_SUCCESS(status
)) {
800 // Create device object for this device.
803 sprintf(ntNameBuffer
,
804 "\\Device\\CdRom%lu",
807 status
= ScsiClassCreateDeviceObject(DriverObject
,
813 if (!NT_SUCCESS(status
)) {
814 DebugPrint((1,"CreateCdRomDeviceObjects: Can not create device %s\n",
817 goto CreateCdRomDeviceObjectExit
;
821 // Indicate that IRPs should include MDLs.
824 deviceObject
->Flags
|= DO_DIRECT_IO
;
827 // Set up required stack size in device object.
830 deviceObject
->StackSize
= PortDeviceObject
->StackSize
+ 2;
832 deviceExtension
= deviceObject
->DeviceExtension
;
835 // Allocate spinlock for split request completion.
838 KeInitializeSpinLock(&deviceExtension
->SplitRequestSpinLock
);
841 // This is the physical device.
844 deviceExtension
->PhysicalDevice
= deviceObject
;
847 // Initialize lock count to zero. The lock count is used to
848 // disable the ejection mechanism when media is mounted.
851 deviceExtension
->LockCount
= 0;
854 // Save system cdrom number
857 deviceExtension
->DeviceNumber
= *DeviceCount
;
860 // Copy port device object to device extension.
863 deviceExtension
->PortDeviceObject
= PortDeviceObject
;
866 // Set the alignment requirements for the device based on the
867 // host adapter requirements
870 if (PortDeviceObject
->AlignmentRequirement
> deviceObject
->AlignmentRequirement
) {
871 deviceObject
->AlignmentRequirement
= PortDeviceObject
->AlignmentRequirement
;
875 // Save address of port driver capabilities.
878 deviceExtension
->PortCapabilities
= PortCapabilities
;
884 deviceExtension
->SrbFlags
= 0;
885 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
888 // Allocate request sense buffer.
891 senseData
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
893 if (senseData
== NULL
) {
896 // The buffer cannot be allocated.
899 status
= STATUS_INSUFFICIENT_RESOURCES
;
900 goto CreateCdRomDeviceObjectExit
;
904 // Set the sense data pointer in the device extension.
907 deviceExtension
->SenseData
= senseData
;
910 // CDROMs are not partitionable so starting offset is 0.
913 deviceExtension
->StartingOffset
.LowPart
= 0;
914 deviceExtension
->StartingOffset
.HighPart
= 0;
917 // Path/TargetId/LUN describes a device location on the SCSI bus.
918 // This information comes from the LunInfo buffer.
921 deviceExtension
->PortNumber
= (UCHAR
)PortNumber
;
922 deviceExtension
->PathId
= LunInfo
->PathId
;
923 deviceExtension
->TargetId
= LunInfo
->TargetId
;
924 deviceExtension
->Lun
= LunInfo
->Lun
;
927 // Set timeout value in seconds.
930 timeOut
= ScsiClassQueryTimeOutRegistryValue(RegistryPath
);
932 deviceExtension
->TimeOutValue
= timeOut
;
934 deviceExtension
->TimeOutValue
= SCSI_CDROM_TIMEOUT
;
938 // Build the lookaside list for srb's for the physical disk. Should only
942 ScsiClassInitializeSrbLookasideList(deviceExtension
,
943 CDROM_SRB_LIST_SIZE
);
945 srbListInitialized
= TRUE
;
948 // Back pointer to device object.
951 deviceExtension
->DeviceObject
= deviceObject
;
954 // Allocate buffer for drive geometry.
957 deviceExtension
->DiskGeometry
=
958 ExAllocatePool(NonPagedPool
, sizeof(DISK_GEOMETRY
));
960 if (deviceExtension
->DiskGeometry
== NULL
) {
962 status
= STATUS_INSUFFICIENT_RESOURCES
;
963 goto CreateCdRomDeviceObjectExit
;
967 // Set up media change support defaults.
970 cddata
= (PCDROM_DATA
)(deviceExtension
+ 1);
972 KeInitializeSpinLock(&cddata
->FormSpinLock
);
973 KeInitializeSpinLock(&cddata
->TimerIrpSpinLock
);
974 InitializeListHead(&cddata
->TimerIrpList
);
976 cddata
->MediaChangeCountDown
= MEDIA_CHANGE_DEFAULT_TIME
;
977 cddata
->MediaChangeSupported
= FALSE
;
978 cddata
->MediaChange
= FALSE
;
981 // Assume that there is initially no media in the device
982 // only notify upper layers if there is something there
985 deviceExtension
->MediaChangeNoMedia
= TRUE
;
986 cddata
->MediaChangeIrp
= NULL
;
988 cddata
->MediaChangeIrpTimeInUse
= 0;
989 cddata
->MediaChangeIrpLost
= FALSE
;
993 // Scan for Scsi controllers that require special processing.
996 ScanForSpecial(deviceObject
,
997 (PINQUIRYDATA
) LunInfo
->InquiryData
,
1001 // Do READ CAPACITY. This SCSI command
1002 // returns the last sector address on the device
1003 // and the bytes per sector.
1004 // These are used to calculate the drive capacity
1008 status
= ScsiClassReadDriveCapacity(deviceObject
);
1009 bps
= deviceExtension
->DiskGeometry
->BytesPerSector
;
1011 if (!NT_SUCCESS(status
) || !bps
) {
1014 "CreateCdRomDeviceObjects: Can't read capacity for device %s\n",
1018 // Set disk geometry to default values (per ISO 9660).
1022 deviceExtension
->SectorShift
= 11;
1023 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(0x7fffffff);
1027 // Insure that bytes per sector is a power of 2
1028 // This corrects a problem with the HP 4020i CDR where it
1029 // returns an incorrect number for bytes per sector.
1032 lastBit
= (ULONG
) -1;
1040 deviceExtension
->DiskGeometry
->BytesPerSector
= bps
;
1041 DebugPrint((2, "CreateCdRomDeviceObject: Calc'd bps = %x\n", bps
));
1044 // Check to see if this is some sort of changer device
1047 changerDevice
= FALSE
;
1050 // Search for devices that have special requirements for media
1054 if (deviceExtension
->Lun
> 0) {
1055 changerDevice
= TRUE
;
1058 if (!changerDevice
) {
1059 changerDevice
= IsThisASanyo(deviceObject
, deviceExtension
->PathId
,
1060 deviceExtension
->TargetId
);
1063 if (!changerDevice
) {
1065 changerDevice
= IsThisAnAtapiChanger(deviceObject
, &tmp
);
1068 if (!changerDevice
) {
1069 changerDevice
= IsThisAMultiLunDevice(deviceObject
, PortDeviceObject
);
1073 // If it is a changer device, increment the timeout to take platter-swapping
1074 // time into account
1078 deviceExtension
->TimeOutValue
+= SCSI_CHANGER_BONUS_TIMEOUT
;
1082 // Create the media change named event. If this succeeds then continue
1083 // initializing the media change support data items.
1086 CdRomCreateNamedEvent(deviceExtension
,*DeviceCount
);
1087 if (deviceExtension
->MediaChangeEvent
) {
1090 // If this is not a changer, get an IRP for the timer request
1091 // and initialize the timer.
1094 if (!changerDevice
) {
1097 // Not a changer device - continue with media change initialization.
1098 // Determine if the user actually wants media change events.
1101 if (CdRomCheckRegistryForMediaChangeValue(RegistryPath
, *DeviceCount
)) {
1102 PIO_STACK_LOCATION irpStack
;
1103 PSCSI_REQUEST_BLOCK srb
;
1107 // User wants it - preallocate IRP and SRB.
1110 irp
= IoAllocateIrp((CCHAR
)(deviceObject
->StackSize
+1),
1115 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
1116 buffer
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
1118 if (srb
&& buffer
) {
1122 // All resources have been allocated set up the IRP.
1125 IoSetNextIrpStackLocation(irp
);
1126 irpStack
= IoGetCurrentIrpStackLocation(irp
);
1127 irpStack
->DeviceObject
= deviceObject
;
1128 irpStack
= IoGetNextIrpStackLocation(irp
);
1129 cddata
->MediaChangeIrp
= irp
;
1130 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1133 // Initialize the SRB
1136 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
1139 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
* 2;
1140 srb
->QueueTag
= SP_UNTAGGED
;
1141 srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
1142 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1143 srb
->PathId
= deviceExtension
->PathId
;
1144 srb
->TargetId
= deviceExtension
->TargetId
;
1145 srb
->Lun
= deviceExtension
->Lun
;
1146 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1149 // Initialize and set up the sense information buffer
1152 RtlZeroMemory(buffer
, SENSE_BUFFER_SIZE
);
1153 srb
->SenseInfoBuffer
= buffer
;
1154 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1157 // Initialize the CDB
1160 cdb
= (PCDB
)&srb
->Cdb
[0];
1161 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_TEST_UNIT_READY
;
1162 cdb
->CDB6GENERIC
.LogicalUnitNumber
= deviceExtension
->Lun
;
1165 // It is ok to support media change events on this device.
1168 cddata
->MediaChangeSupported
= TRUE
;
1169 cddata
->MediaChange
= TRUE
;
1183 deviceExtension
->MediaChangeEvent
= NULL
;
1186 deviceExtension
->MediaChangeEvent
= NULL
;
1191 // Assume use of 6-byte mode sense/select for now.
1194 cddata
->XAFlags
|= XA_USE_6_BYTE
;
1197 // Build and issue mode sense with Read error recovery page. This will be used to change
1198 // block size in case of any raw reads (Mode 2, Form 2).
1201 length
= (sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH
);
1203 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
1206 cdb
= (PCDB
)srb
.Cdb
;
1209 // Set timeout value from device extension.
1212 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
1215 // Build the MODE SENSE CDB. The data returned will be kept in the device extension
1216 // and used to set block size.
1219 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
1220 cdb
->MODE_SENSE
.PageCode
= 0x1;
1221 cdb
->MODE_SENSE
.AllocationLength
= (UCHAR
)length
;
1223 buffer
= ExAllocatePool(NonPagedPoolCacheAligned
, (sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH10
));
1225 status
= STATUS_INSUFFICIENT_RESOURCES
;
1226 goto CreateCdRomDeviceObjectExit
;
1229 status
= ScsiClassSendSrbSynchronous(deviceObject
,
1234 if (!NT_SUCCESS(status
)) {
1237 // May be Atapi, try 10-byte.
1240 length
= (sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH10
);
1242 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
1245 // Build the MODE SENSE CDB.
1249 cdb
= (PCDB
)srb
.Cdb
;
1252 // Set timeout value from device extension.
1255 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
1257 cdb
->MODE_SENSE10
.OperationCode
= SCSIOP_MODE_SENSE10
;
1258 cdb
->MODE_SENSE10
.PageCode
= 0x1;
1260 cdb
->MODE_SENSE10
.AllocationLength
[0] = (UCHAR
)(length
>> 8);
1261 cdb
->MODE_SENSE10
.AllocationLength
[1] = (UCHAR
)(length
& 0xFF);
1263 status
= ScsiClassSendSrbSynchronous(deviceObject
,
1268 if (status
== STATUS_DATA_OVERRUN
) {
1271 // Build and issue the ReadCd command to ensure that this device supports it.
1274 RtlZeroMemory(cdb
, 12);
1276 cdb
->READ_CD
.OperationCode
= SCSIOP_READ_CD
;
1278 status
= ScsiClassSendSrbSynchronous(deviceObject
,
1285 // If the command wasn't rejected then support the READ_CD.
1288 if (NT_SUCCESS(status
) || (status
== STATUS_NO_MEDIA_IN_DEVICE
)) {
1291 // Using Read CD precludes issueing a mode select to
1292 // set the user data size. So, no buffer copy is
1296 cddata
->XAFlags
&= ~XA_USE_6_BYTE
;
1297 cddata
->XAFlags
= XA_USE_READ_CD
| XA_USE_10_BYTE
;
1300 RtlCopyMemory(&cddata
->u1
.Header
, buffer
, sizeof(ERROR_RECOVERY_DATA10
));
1301 cddata
->u1
.Header
.ModeDataLength
= 0;
1303 cddata
->XAFlags
&= ~XA_USE_6_BYTE
;
1304 cddata
->XAFlags
|= XA_USE_10_BYTE
;
1307 } else if (NT_SUCCESS(status
)) {
1309 RtlCopyMemory(&cddata
->u1
.Header
, buffer
, sizeof(ERROR_RECOVERY_DATA10
));
1310 cddata
->u1
.Header
.ModeDataLength
= 0;
1312 cddata
->XAFlags
&= ~XA_USE_6_BYTE
;
1313 cddata
->XAFlags
|= XA_USE_10_BYTE
;
1316 cddata
->XAFlags
|= XA_NOT_SUPPORTED
;
1319 RtlCopyMemory(&cddata
->u1
.Header
, buffer
, sizeof(ERROR_RECOVERY_DATA
));
1320 cddata
->u1
.Header
.ModeDataLength
= 0;
1326 // Start the timer now regardless of if Autorun is enabled.
1327 // The timer must run forever since IoStopTimer faults.
1330 IoInitializeTimer(deviceObject
, CdRomTickHandler
, NULL
);
1331 IoStartTimer(deviceObject
);
1333 return(STATUS_SUCCESS
);
1335 CreateCdRomDeviceObjectExit
:
1338 // Release the device since an error occured.
1341 ScsiClassClaimDevice(PortDeviceObject
,
1346 if (senseData
!= NULL
) {
1347 ExFreePool(senseData
);
1350 if (deviceExtension
->DiskGeometry
!= NULL
) {
1351 ExFreePool(deviceExtension
->DiskGeometry
);
1354 if (deviceObject
!= NULL
) {
1355 if (srbListInitialized
) {
1356 ExDeleteNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
);
1358 IoDeleteDevice(deviceObject
);
1364 } // end CreateCdRomDeviceObject()
1369 IN PDEVICE_OBJECT DeviceObject
,
1374 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1375 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1376 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
1377 PIO_STACK_LOCATION irpStack
;
1379 ULONG transferPages
;
1380 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
1381 ULONG maximumTransferLength
= deviceExtension
->PortCapabilities
->MaximumTransferLength
;
1383 PSCSI_REQUEST_BLOCK srb
= NULL
;
1385 PUCHAR senseBuffer
= NULL
;
1391 // Mark IRP with status pending.
1394 IoMarkIrpPending(Irp
);
1397 // If the flag is set in the device object, force a verify.
1400 if (DeviceObject
->Flags
& DO_VERIFY_VOLUME
) {
1401 DebugPrint((2, "ScsiCdRomStartIo: [%lx] Volume needs verified\n", Irp
));
1402 if (!(currentIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
)) {
1404 if (Irp
->Tail
.Overlay
.Thread
) {
1405 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
1408 Irp
->IoStatus
.Status
= STATUS_VERIFY_REQUIRED
;
1410 DebugPrint((2, "ScsiCdRomStartIo: [%lx] Calling UpdateCapcity - "
1411 "ioctl event = %lx\n",
1413 nextIrpStack
->Parameters
.Others
.Argument1
1417 // our device control dispatch routine stores an event in the next
1418 // stack location to signal when startio has completed. We need to
1419 // pass this in so that the update capacity completion routine can
1420 // set it rather than completing the Irp.
1423 status
= CdRomUpdateCapacity(deviceExtension
,
1425 nextIrpStack
->Parameters
.Others
.Argument1
1428 DebugPrint((2, "ScsiCdRomStartIo: [%lx] UpdateCapacity returned %lx\n", Irp
, status
));
1429 ASSERT(status
== STATUS_PENDING
);
1434 cdData
= (PCDROM_DATA
)(deviceExtension
+ 1);
1435 use6Byte
= cdData
->XAFlags
& XA_USE_6_BYTE
;
1437 if (currentIrpStack
->MajorFunction
== IRP_MJ_READ
) {
1440 // Add partition byte offset to make starting byte relative to
1441 // beginning of disk. In addition, add in skew for DM Driver, if any.
1444 currentIrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+= (deviceExtension
->StartingOffset
.QuadPart
);
1447 // Calculate number of pages in this transfer.
1450 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp
->MdlAddress
),
1451 currentIrpStack
->Parameters
.Read
.Length
);
1454 // Check if request length is greater than the maximum number of
1455 // bytes that the hardware can transfer.
1458 if (cdData
->RawAccess
) {
1460 ASSERT(!(cdData
->XAFlags
& XA_USE_READ_CD
));
1463 // Fire off a mode select to switch back to cooked sectors.
1466 irp2
= IoAllocateIrp((CCHAR
)(deviceExtension
->DeviceObject
->StackSize
+1),
1470 Irp
->IoStatus
.Information
= 0;
1471 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1472 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1473 IoStartNextPacket(DeviceObject
, FALSE
);
1477 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
1479 Irp
->IoStatus
.Information
= 0;
1480 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1481 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1483 IoStartNextPacket(DeviceObject
, FALSE
);
1487 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
1489 cdb
= (PCDB
)srb
->Cdb
;
1492 // Allocate sense buffer.
1495 senseBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
1498 Irp
->IoStatus
.Information
= 0;
1499 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1500 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1503 IoStartNextPacket(DeviceObject
, FALSE
);
1511 IoSetNextIrpStackLocation(irp2
);
1512 irp2
->IoStatus
.Status
= STATUS_SUCCESS
;
1513 irp2
->IoStatus
.Information
= 0;
1515 irp2
->UserBuffer
= NULL
;
1518 // Save the device object and irp in a private stack location.
1521 irpStack
= IoGetCurrentIrpStackLocation(irp2
);
1522 irpStack
->DeviceObject
= deviceExtension
->DeviceObject
;
1523 irpStack
->Parameters
.Others
.Argument2
= (PVOID
) Irp
;
1526 // The retry count will be in the real Irp, as the retry logic will
1527 // recreate our private irp.
1530 if (!(nextIrpStack
->Parameters
.Others
.Argument1
)) {
1533 // Only jam this in if it doesn't exist. The completion routines can
1534 // call StartIo directly in the case of retries and resetting it will
1535 // cause infinite loops.
1538 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
1542 // Construct the IRP stack for the lower level driver.
1545 irpStack
= IoGetNextIrpStackLocation(irp2
);
1546 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
1547 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
1548 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1550 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1551 srb
->PathId
= deviceExtension
->PathId
;
1552 srb
->TargetId
= deviceExtension
->TargetId
;
1553 srb
->Lun
= deviceExtension
->Lun
;
1554 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1555 srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
1556 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
1558 srb
->OriginalRequest
= irp2
;
1559 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1560 srb
->SenseInfoBuffer
= senseBuffer
;
1562 transferByteCount
= (use6Byte
) ? sizeof(ERROR_RECOVERY_DATA
) : sizeof(ERROR_RECOVERY_DATA10
);
1563 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, transferByteCount
);
1565 Irp
->IoStatus
.Information
= 0;
1566 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1567 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1568 ExFreePool(senseBuffer
);
1571 IoStartNextPacket(DeviceObject
, FALSE
);
1576 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
1582 if (!irp2
->MdlAddress
) {
1583 Irp
->IoStatus
.Information
= 0;
1584 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1585 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1586 ExFreePool(senseBuffer
);
1588 ExFreePool(dataBuffer
);
1590 IoStartNextPacket(DeviceObject
, FALSE
);
1598 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
1600 srb
->DataBuffer
= dataBuffer
;
1603 // Set the new block size in the descriptor.
1606 cdData
->u1
.BlockDescriptor
.BlockLength
[0] = (UCHAR
)(COOKED_SECTOR_SIZE
>> 16) & 0xFF;
1607 cdData
->u1
.BlockDescriptor
.BlockLength
[1] = (UCHAR
)(COOKED_SECTOR_SIZE
>> 8) & 0xFF;
1608 cdData
->u1
.BlockDescriptor
.BlockLength
[2] = (UCHAR
)(COOKED_SECTOR_SIZE
& 0xFF);
1611 // Move error page into dataBuffer.
1614 RtlCopyMemory(srb
->DataBuffer
, &cdData
->u1
.Header
, transferByteCount
);
1617 // Build and send a mode select to switch into raw mode.
1620 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
1621 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_OUT
);
1622 srb
->DataTransferLength
= transferByteCount
;
1623 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
* 2;
1627 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
1628 cdb
->MODE_SELECT
.PFBit
= 1;
1629 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)transferByteCount
;
1632 srb
->CdbLength
= 10;
1633 cdb
->MODE_SELECT10
.OperationCode
= SCSIOP_MODE_SELECT10
;
1634 cdb
->MODE_SELECT10
.PFBit
= 1;
1635 cdb
->MODE_SELECT10
.ParameterListLength
[0] = (UCHAR
)(transferByteCount
>> 8);
1636 cdb
->MODE_SELECT10
.ParameterListLength
[1] = (UCHAR
)(transferByteCount
& 0xFF);
1640 // Update completion routine.
1643 IoSetCompletionRoutine(irp2
,
1644 CdRomSwitchModeCompletion
,
1650 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
1654 if ((currentIrpStack
->Parameters
.Read
.Length
> maximumTransferLength
) ||
1656 deviceExtension
->PortCapabilities
->MaximumPhysicalPages
)) {
1659 // Request needs to be split. Completion of each portion of the
1660 // request will fire off the next portion. The final request will
1661 // signal Io to send a new request.
1665 deviceExtension
->PortCapabilities
->MaximumPhysicalPages
- 1;
1667 if(maximumTransferLength
> transferPages
<< PAGE_SHIFT
) {
1668 maximumTransferLength
= transferPages
<< PAGE_SHIFT
;
1672 // Check that the maximum transfer size is not zero
1675 if(maximumTransferLength
== 0) {
1676 maximumTransferLength
= PAGE_SIZE
;
1679 ScsiClassSplitRequest(DeviceObject
, Irp
, maximumTransferLength
);
1685 // Build SRB and CDB for this IRP.
1688 ScsiClassBuildRequest(DeviceObject
, Irp
);
1693 } else if (currentIrpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
) {
1696 // Allocate an irp, srb and associated structures.
1699 irp2
= IoAllocateIrp((CCHAR
)(deviceExtension
->DeviceObject
->StackSize
+1),
1703 Irp
->IoStatus
.Information
= 0;
1704 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1705 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1706 IoStartNextPacket(DeviceObject
, FALSE
);
1707 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp
, Irp
->IoStatus
.Status
, __LINE__
));
1711 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
1713 Irp
->IoStatus
.Information
= 0;
1714 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1715 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1717 IoStartNextPacket(DeviceObject
, FALSE
);
1718 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp
, Irp
->IoStatus
.Status
, __LINE__
));
1722 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
1724 cdb
= (PCDB
)srb
->Cdb
;
1727 // Allocate sense buffer.
1730 senseBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
1733 Irp
->IoStatus
.Information
= 0;
1734 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1735 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1738 IoStartNextPacket(DeviceObject
, FALSE
);
1739 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp
, Irp
->IoStatus
.Status
, __LINE__
));
1747 IoSetNextIrpStackLocation(irp2
);
1748 irp2
->IoStatus
.Status
= STATUS_SUCCESS
;
1749 irp2
->IoStatus
.Information
= 0;
1751 irp2
->UserBuffer
= NULL
;
1754 // Save the device object and irp in a private stack location.
1757 irpStack
= IoGetCurrentIrpStackLocation(irp2
);
1758 irpStack
->DeviceObject
= deviceExtension
->DeviceObject
;
1759 irpStack
->Parameters
.Others
.Argument2
= (PVOID
) Irp
;
1762 // The retry count will be in the real Irp, as the retry logic will
1763 // recreate our private irp.
1766 if (!(nextIrpStack
->Parameters
.Others
.Argument1
)) {
1769 // Only jam this in if it doesn't exist. The completion routines can
1770 // call StartIo directly in the case of retries and resetting it will
1771 // cause infinite loops.
1774 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
1778 // Construct the IRP stack for the lower level driver.
1781 irpStack
= IoGetNextIrpStackLocation(irp2
);
1782 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
1783 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
1784 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1786 IoSetCompletionRoutine(irp2
,
1787 CdRomDeviceControlCompletion
,
1793 // Setup those fields that are generic to all requests.
1796 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1797 srb
->PathId
= deviceExtension
->PathId
;
1798 srb
->TargetId
= deviceExtension
->TargetId
;
1799 srb
->Lun
= deviceExtension
->Lun
;
1800 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1801 srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
1802 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
1804 srb
->OriginalRequest
= irp2
;
1805 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1806 srb
->SenseInfoBuffer
= senseBuffer
;
1808 switch (currentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
) {
1810 case IOCTL_CDROM_RAW_READ
: {
1813 // Determine whether the drive is currently in raw or cooked mode,
1814 // and which command to use to read the data.
1817 if (!(cdData
->XAFlags
& XA_USE_READ_CD
)) {
1819 PRAW_READ_INFO rawReadInfo
=
1820 (PRAW_READ_INFO
)currentIrpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
1821 ULONG maximumTransferLength
;
1822 ULONG transferPages
;
1824 if (cdData
->RawAccess
) {
1826 ULONG startingSector
;
1829 // Free the recently allocated irp, as we don't need it.
1834 cdb
= (PCDB
)srb
->Cdb
;
1835 RtlZeroMemory(cdb
, 12);
1838 // Calculate starting offset.
1841 startingSector
= (ULONG
)(rawReadInfo
->DiskOffset
.QuadPart
>> deviceExtension
->SectorShift
);
1842 transferByteCount
= rawReadInfo
->SectorCount
* RAW_SECTOR_SIZE
;
1843 maximumTransferLength
= deviceExtension
->PortCapabilities
->MaximumTransferLength
;
1844 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp
->MdlAddress
),
1848 // Determine if request is within limits imposed by miniport.
1851 if (transferByteCount
> maximumTransferLength
||
1852 transferPages
> deviceExtension
->PortCapabilities
->MaximumPhysicalPages
) {
1855 // The claim is that this won't happen, and is backed up by
1856 // ActiveMovie usage, which does unbuffered XA reads of 0x18000, yet
1857 // we get only 4 sector requests.
1861 Irp
->IoStatus
.Information
= 0;
1862 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
1863 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1864 ExFreePool(senseBuffer
);
1866 IoStartNextPacket(DeviceObject
, FALSE
);
1871 srb
->OriginalRequest
= Irp
;
1872 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
1873 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
1874 srb
->DataTransferLength
= transferByteCount
;
1875 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
1876 srb
->CdbLength
= 10;
1877 srb
->DataBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
1879 if (rawReadInfo
->TrackMode
== CDDA
) {
1880 if (cdData
->XAFlags
& PLEXTOR_CDDA
) {
1882 srb
->CdbLength
= 12;
1884 cdb
->PLXTR_READ_CDDA
.LogicalUnitNumber
= deviceExtension
->Lun
;
1885 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
1886 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
1887 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
1888 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
1890 cdb
->PLXTR_READ_CDDA
.TransferBlockByte3
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
1891 cdb
->PLXTR_READ_CDDA
.TransferBlockByte2
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
1892 cdb
->PLXTR_READ_CDDA
.TransferBlockByte1
= 0;
1893 cdb
->PLXTR_READ_CDDA
.TransferBlockByte0
= 0;
1895 cdb
->PLXTR_READ_CDDA
.SubCode
= 0;
1896 cdb
->PLXTR_READ_CDDA
.OperationCode
= 0xD8;
1898 } else if (cdData
->XAFlags
& NEC_CDDA
) {
1900 cdb
->NEC_READ_CDDA
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
1901 cdb
->NEC_READ_CDDA
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
1902 cdb
->NEC_READ_CDDA
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
1903 cdb
->NEC_READ_CDDA
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
1905 cdb
->NEC_READ_CDDA
.TransferBlockByte1
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
1906 cdb
->NEC_READ_CDDA
.TransferBlockByte0
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
1908 cdb
->NEC_READ_CDDA
.OperationCode
= 0xD4;
1912 cdb
->CDB10
.LogicalUnitNumber
= deviceExtension
->Lun
;
1914 cdb
->CDB10
.TransferBlocksMsb
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
1915 cdb
->CDB10
.TransferBlocksLsb
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
1917 cdb
->CDB10
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
1918 cdb
->CDB10
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
1919 cdb
->CDB10
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
1920 cdb
->CDB10
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
1922 cdb
->CDB10
.OperationCode
= SCSIOP_READ
;
1925 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
1927 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
1928 nextIrpStack
->Parameters
.Scsi
.Srb
= srb
;
1930 if (!(nextIrpStack
->Parameters
.Others
.Argument1
)) {
1933 // Only jam this in if it doesn't exist. The completion routines can
1934 // call StartIo directly in the case of retries and resetting it will
1935 // cause infinite loops.
1938 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
1942 // Set up IoCompletion routine address.
1945 IoSetCompletionRoutine(Irp
,
1952 IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
1957 transferByteCount
= (use6Byte
) ? sizeof(ERROR_RECOVERY_DATA
) : sizeof(ERROR_RECOVERY_DATA10
);
1958 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, transferByteCount
);
1960 Irp
->IoStatus
.Information
= 0;
1961 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1962 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1963 ExFreePool(senseBuffer
);
1966 IoStartNextPacket(DeviceObject
, FALSE
);
1971 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
1977 if (!irp2
->MdlAddress
) {
1978 Irp
->IoStatus
.Information
= 0;
1979 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1980 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1981 ExFreePool(senseBuffer
);
1983 ExFreePool(dataBuffer
);
1985 IoStartNextPacket(DeviceObject
, FALSE
);
1993 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
1995 srb
->DataBuffer
= dataBuffer
;
1998 // Set the new block size in the descriptor.
2001 cdData
->u1
.BlockDescriptor
.BlockLength
[0] = (UCHAR
)(RAW_SECTOR_SIZE
>> 16) & 0xFF;
2002 cdData
->u1
.BlockDescriptor
.BlockLength
[1] = (UCHAR
)(RAW_SECTOR_SIZE
>> 8) & 0xFF;
2003 cdData
->u1
.BlockDescriptor
.BlockLength
[2] = (UCHAR
)(RAW_SECTOR_SIZE
& 0xFF);
2007 // TODO: Set density code, based on operation
2010 cdData
->u1
.BlockDescriptor
.DensityCode
= 0;
2014 // Move error page into dataBuffer.
2017 RtlCopyMemory(srb
->DataBuffer
, &cdData
->u1
.Header
, transferByteCount
);
2021 // Build and send a mode select to switch into raw mode.
2024 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2025 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_OUT
);
2026 srb
->DataTransferLength
= transferByteCount
;
2027 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
* 2;
2031 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
2032 cdb
->MODE_SELECT
.PFBit
= 1;
2033 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)transferByteCount
;
2036 srb
->CdbLength
= 10;
2037 cdb
->MODE_SELECT10
.OperationCode
= SCSIOP_MODE_SELECT10
;
2038 cdb
->MODE_SELECT10
.PFBit
= 1;
2039 cdb
->MODE_SELECT10
.ParameterListLength
[0] = (UCHAR
)(transferByteCount
>> 8);
2040 cdb
->MODE_SELECT10
.ParameterListLength
[1] = (UCHAR
)(transferByteCount
& 0xFF);
2044 // Update completion routine.
2047 IoSetCompletionRoutine(irp2
,
2048 CdRomSwitchModeCompletion
,
2058 PRAW_READ_INFO rawReadInfo
=
2059 (PRAW_READ_INFO
)currentIrpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
2060 ULONG startingSector
;
2063 // Free the recently allocated irp, as we don't need it.
2068 cdb
= (PCDB
)srb
->Cdb
;
2069 RtlZeroMemory(cdb
, 12);
2073 // Calculate starting offset.
2076 startingSector
= (ULONG
)(rawReadInfo
->DiskOffset
.QuadPart
>> deviceExtension
->SectorShift
);
2077 transferByteCount
= rawReadInfo
->SectorCount
* RAW_SECTOR_SIZE
;
2080 srb
->OriginalRequest
= Irp
;
2081 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2082 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
2083 srb
->DataTransferLength
= transferByteCount
;
2084 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2085 srb
->DataBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
2086 srb
->CdbLength
= 12;
2087 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
2090 // Fill in CDB fields.
2093 cdb
= (PCDB
)srb
->Cdb
;
2096 cdb
->READ_CD
.TransferBlocks
[2] = (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
2097 cdb
->READ_CD
.TransferBlocks
[1] = (UCHAR
) (rawReadInfo
->SectorCount
>> 8 );
2098 cdb
->READ_CD
.TransferBlocks
[0] = (UCHAR
) (rawReadInfo
->SectorCount
>> 16);
2101 cdb
->READ_CD
.StartingLBA
[3] = (UCHAR
) (startingSector
& 0xFF);
2102 cdb
->READ_CD
.StartingLBA
[2] = (UCHAR
) ((startingSector
>> 8));
2103 cdb
->READ_CD
.StartingLBA
[1] = (UCHAR
) ((startingSector
>> 16));
2104 cdb
->READ_CD
.StartingLBA
[0] = (UCHAR
) ((startingSector
>> 24));
2107 // Setup cdb depending upon the sector type we want.
2110 switch (rawReadInfo
->TrackMode
) {
2113 cdb
->READ_CD
.ExpectedSectorType
= CD_DA_SECTOR
;
2114 cdb
->READ_CD
.IncludeUserData
= 1;
2115 cdb
->READ_CD
.HeaderCode
= 3;
2116 cdb
->READ_CD
.IncludeSyncData
= 1;
2121 cdb
->READ_CD
.ExpectedSectorType
= YELLOW_MODE2_SECTOR
;
2122 cdb
->READ_CD
.IncludeUserData
= 1;
2123 cdb
->READ_CD
.HeaderCode
= 1;
2124 cdb
->READ_CD
.IncludeSyncData
= 1;
2129 cdb
->READ_CD
.ExpectedSectorType
= FORM2_MODE2_SECTOR
;
2130 cdb
->READ_CD
.IncludeUserData
= 1;
2131 cdb
->READ_CD
.HeaderCode
= 3;
2132 cdb
->READ_CD
.IncludeSyncData
= 1;
2136 Irp
->IoStatus
.Information
= 0;
2137 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
2138 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2139 ExFreePool(senseBuffer
);
2142 IoStartNextPacket(DeviceObject
, FALSE
);
2143 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp
, Irp
->IoStatus
.Status
, __LINE__
));
2147 cdb
->READ_CD
.OperationCode
= SCSIOP_READ_CD
;
2149 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
2150 nextIrpStack
->Parameters
.Scsi
.Srb
= srb
;
2152 if (!(nextIrpStack
->Parameters
.Others
.Argument1
)) {
2155 // Only jam this in if it doesn't exist. The completion routines can
2156 // call StartIo directly in the case of retries and resetting it will
2157 // cause infinite loops.
2160 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
2164 // Set up IoCompletion routine address.
2167 IoSetCompletionRoutine(Irp
,
2174 IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
2179 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2183 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
: {
2186 // Issue ReadCapacity to update device extension
2187 // with information for current media.
2191 "CdRomStartIo: Get drive capacity\n"));
2194 // setup remaining srb and cdb parameters.
2197 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2198 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
2199 srb
->DataTransferLength
= sizeof(READ_CAPACITY_DATA
);
2200 srb
->CdbLength
= 10;
2201 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2203 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, sizeof(READ_CAPACITY_DATA
));
2205 Irp
->IoStatus
.Information
= 0;
2206 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2207 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2208 ExFreePool(senseBuffer
);
2211 IoStartNextPacket(DeviceObject
, FALSE
);
2212 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp
, Irp
->IoStatus
.Status
, __LINE__
));
2217 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2218 sizeof(READ_CAPACITY_DATA
),
2223 if (!irp2
->MdlAddress
) {
2224 Irp
->IoStatus
.Information
= 0;
2225 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2226 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2227 ExFreePool(senseBuffer
);
2229 ExFreePool(dataBuffer
);
2231 IoStartNextPacket(DeviceObject
, FALSE
);
2232 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp
, Irp
->IoStatus
.Status
, __LINE__
));
2240 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2242 srb
->DataBuffer
= dataBuffer
;
2243 cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
2245 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2249 case IOCTL_CDROM_CHECK_VERIFY
: {
2252 // Since a test unit ready is about to be performed, reset the timer
2253 // value to decrease the opportunities for it to race with this code.
2256 cdData
->MediaChangeCountDown
= MEDIA_CHANGE_DEFAULT_TIME
;
2259 // Set up the SRB/CDB
2263 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_TEST_UNIT_READY
;
2264 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
* 2;
2265 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2266 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_NO_DATA_TRANSFER
);
2268 DebugPrint((2, "ScsiCdRomStartIo: [%lx] Sending CHECK_VERIFY irp %lx\n", Irp
, irp2
));
2269 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2273 case IOCTL_CDROM_GET_LAST_SESSION
:
2276 // Set format to return first and last session numbers.
2279 cdb
->READ_TOC
.Format
= GET_LAST_SESSION
;
2282 // Fall through to READ TOC code.
2285 case IOCTL_CDROM_READ_TOC
: {
2288 if (currentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_READ_TOC
) {
2291 // Use MSF addressing if not request for session information.
2294 cdb
->READ_TOC
.Msf
= CDB_USE_MSF
;
2298 // Set size of TOC structure.
2302 currentIrpStack
->Parameters
.Read
.Length
>
2303 sizeof(CDROM_TOC
) ? sizeof(CDROM_TOC
):
2304 currentIrpStack
->Parameters
.Read
.Length
;
2306 cdb
->READ_TOC
.AllocationLength
[0] = (UCHAR
) (transferByteCount
>> 8);
2307 cdb
->READ_TOC
.AllocationLength
[1] = (UCHAR
) (transferByteCount
& 0xFF);
2309 cdb
->READ_TOC
.Control
= 0;
2312 // Start at beginning of disc.
2315 cdb
->READ_TOC
.StartingTrack
= 0;
2318 // setup remaining srb and cdb parameters.
2321 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2322 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
2323 srb
->DataTransferLength
= transferByteCount
;
2324 srb
->CdbLength
= 10;
2325 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2327 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, transferByteCount
);
2329 Irp
->IoStatus
.Information
= 0;
2330 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2331 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2332 ExFreePool(senseBuffer
);
2335 IoStartNextPacket(DeviceObject
, FALSE
);
2340 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2346 if (!irp2
->MdlAddress
) {
2347 Irp
->IoStatus
.Information
= 0;
2348 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2349 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2350 ExFreePool(senseBuffer
);
2352 ExFreePool(dataBuffer
);
2354 IoStartNextPacket(DeviceObject
, FALSE
);
2362 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2364 srb
->DataBuffer
= dataBuffer
;
2365 cdb
->READ_TOC
.OperationCode
= SCSIOP_READ_TOC
;
2367 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2372 case IOCTL_CDROM_PLAY_AUDIO_MSF
: {
2374 PCDROM_PLAY_AUDIO_MSF inputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
2377 // Set up the SRB/CDB
2380 srb
->CdbLength
= 10;
2381 cdb
->PLAY_AUDIO_MSF
.OperationCode
= SCSIOP_PLAY_AUDIO_MSF
;
2383 cdb
->PLAY_AUDIO_MSF
.StartingM
= inputBuffer
->StartingM
;
2384 cdb
->PLAY_AUDIO_MSF
.StartingS
= inputBuffer
->StartingS
;
2385 cdb
->PLAY_AUDIO_MSF
.StartingF
= inputBuffer
->StartingF
;
2387 cdb
->PLAY_AUDIO_MSF
.EndingM
= inputBuffer
->EndingM
;
2388 cdb
->PLAY_AUDIO_MSF
.EndingS
= inputBuffer
->EndingS
;
2389 cdb
->PLAY_AUDIO_MSF
.EndingF
= inputBuffer
->EndingF
;
2391 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2392 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2393 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_NO_DATA_TRANSFER
);
2395 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2400 case IOCTL_CDROM_READ_Q_CHANNEL
: {
2402 PCDROM_SUB_Q_DATA_FORMAT inputBuffer
=
2403 Irp
->AssociatedIrp
.SystemBuffer
;
2406 // Allocate buffer for subq channel information.
2409 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
2410 sizeof(SUB_Q_CHANNEL_DATA
));
2413 Irp
->IoStatus
.Information
= 0;
2414 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2415 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2416 ExFreePool(senseBuffer
);
2419 IoStartNextPacket(DeviceObject
, FALSE
);
2424 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2430 if (!irp2
->MdlAddress
) {
2431 Irp
->IoStatus
.Information
= 0;
2432 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2433 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2434 ExFreePool(senseBuffer
);
2436 ExFreePool(dataBuffer
);
2438 IoStartNextPacket(DeviceObject
, FALSE
);
2446 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2448 srb
->DataBuffer
= dataBuffer
;
2451 // Always logical unit 0, but only use MSF addressing
2452 // for IOCTL_CDROM_CURRENT_POSITION
2455 if (inputBuffer
->Format
==IOCTL_CDROM_CURRENT_POSITION
)
2456 cdb
->SUBCHANNEL
.Msf
= CDB_USE_MSF
;
2459 // Return subchannel data
2462 cdb
->SUBCHANNEL
.SubQ
= CDB_SUBCHANNEL_BLOCK
;
2465 // Specify format of informatin to return
2468 cdb
->SUBCHANNEL
.Format
= inputBuffer
->Format
;
2471 // Specify which track to access (only used by Track ISRC reads)
2474 if (inputBuffer
->Format
==IOCTL_CDROM_TRACK_ISRC
) {
2475 cdb
->SUBCHANNEL
.TrackNumber
= inputBuffer
->Track
;
2479 // Set size of channel data -- however, this is dependent on
2480 // what information we are requesting (which Format)
2483 switch( inputBuffer
->Format
) {
2485 case IOCTL_CDROM_CURRENT_POSITION
:
2486 transferByteCount
= sizeof(SUB_Q_CURRENT_POSITION
);
2489 case IOCTL_CDROM_MEDIA_CATALOG
:
2490 transferByteCount
= sizeof(SUB_Q_MEDIA_CATALOG_NUMBER
);
2493 case IOCTL_CDROM_TRACK_ISRC
:
2494 transferByteCount
= sizeof(SUB_Q_TRACK_ISRC
);
2498 cdb
->SUBCHANNEL
.AllocationLength
[0] = (UCHAR
) (transferByteCount
>> 8);
2499 cdb
->SUBCHANNEL
.AllocationLength
[1] = (UCHAR
) (transferByteCount
& 0xFF);
2500 cdb
->SUBCHANNEL
.OperationCode
= SCSIOP_READ_SUB_CHANNEL
;
2501 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2502 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
2503 srb
->DataTransferLength
= transferByteCount
;
2504 srb
->CdbLength
= 10;
2505 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2507 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2512 case IOCTL_CDROM_PAUSE_AUDIO
: {
2514 cdb
->PAUSE_RESUME
.OperationCode
= SCSIOP_PAUSE_RESUME
;
2515 cdb
->PAUSE_RESUME
.Action
= CDB_AUDIO_PAUSE
;
2517 srb
->CdbLength
= 10;
2518 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2519 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2520 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_NO_DATA_TRANSFER
);
2522 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2526 case IOCTL_CDROM_RESUME_AUDIO
: {
2528 cdb
->PAUSE_RESUME
.OperationCode
= SCSIOP_PAUSE_RESUME
;
2529 cdb
->PAUSE_RESUME
.Action
= CDB_AUDIO_RESUME
;
2531 srb
->CdbLength
= 10;
2532 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2533 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2534 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_NO_DATA_TRANSFER
);
2536 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2540 case IOCTL_CDROM_SEEK_AUDIO_MSF
: {
2542 PCDROM_SEEK_AUDIO_MSF inputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
2543 ULONG logicalBlockAddress
;
2545 logicalBlockAddress
= MSF_TO_LBA(inputBuffer
->M
, inputBuffer
->S
, inputBuffer
->F
);
2547 cdb
->SEEK
.OperationCode
= SCSIOP_SEEK
;
2548 cdb
->SEEK
.LogicalBlockAddress
[0] = ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte3
;
2549 cdb
->SEEK
.LogicalBlockAddress
[1] = ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte2
;
2550 cdb
->SEEK
.LogicalBlockAddress
[2] = ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte1
;
2551 cdb
->SEEK
.LogicalBlockAddress
[3] = ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte0
;
2553 srb
->CdbLength
= 10;
2554 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2555 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2556 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_NO_DATA_TRANSFER
);
2558 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2563 case IOCTL_CDROM_STOP_AUDIO
: {
2565 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
2566 cdb
->START_STOP
.Immediate
= 1;
2567 cdb
->START_STOP
.Start
= 0;
2568 cdb
->START_STOP
.LoadEject
= 0;
2571 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2573 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2574 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_NO_DATA_TRANSFER
);
2576 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2580 case IOCTL_CDROM_GET_CONTROL
: {
2582 // Allocate buffer for volume control information.
2585 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
2589 Irp
->IoStatus
.Information
= 0;
2590 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2591 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2592 ExFreePool(senseBuffer
);
2595 IoStartNextPacket(DeviceObject
, FALSE
);
2600 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2606 if (!irp2
->MdlAddress
) {
2607 Irp
->IoStatus
.Information
= 0;
2608 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2609 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2610 ExFreePool(senseBuffer
);
2612 ExFreePool(dataBuffer
);
2614 IoStartNextPacket(DeviceObject
, FALSE
);
2622 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2623 srb
->DataBuffer
= dataBuffer
;
2625 RtlZeroMemory(dataBuffer
, MODE_DATA_SIZE
);
2628 // Setup for either 6 or 10 byte CDBs.
2633 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
2634 cdb
->MODE_SENSE
.PageCode
= CDROM_AUDIO_CONTROL_PAGE
;
2635 cdb
->MODE_SENSE
.AllocationLength
= MODE_DATA_SIZE
;
2638 // Disable block descriptors.
2641 cdb
->MODE_SENSE
.Dbd
= TRUE
;
2646 cdb
->MODE_SENSE10
.OperationCode
= SCSIOP_MODE_SENSE10
;
2647 cdb
->MODE_SENSE10
.PageCode
= CDROM_AUDIO_CONTROL_PAGE
;
2648 cdb
->MODE_SENSE10
.AllocationLength
[0] = (UCHAR
)(MODE_DATA_SIZE
>> 8);
2649 cdb
->MODE_SENSE10
.AllocationLength
[1] = (UCHAR
)(MODE_DATA_SIZE
& 0xFF);
2652 // Disable block descriptors.
2655 cdb
->MODE_SENSE10
.Dbd
= TRUE
;
2657 srb
->CdbLength
= 10;
2660 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2661 srb
->DataTransferLength
= MODE_DATA_SIZE
;
2662 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2663 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
2665 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2670 case IOCTL_CDROM_GET_VOLUME
:
2671 case IOCTL_CDROM_SET_VOLUME
: {
2673 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
2677 Irp
->IoStatus
.Information
= 0;
2678 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2679 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2680 ExFreePool(senseBuffer
);
2683 IoStartNextPacket(DeviceObject
, FALSE
);
2687 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2693 if (!irp2
->MdlAddress
) {
2694 Irp
->IoStatus
.Information
= 0;
2695 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2696 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2697 ExFreePool(senseBuffer
);
2699 ExFreePool(dataBuffer
);
2701 IoStartNextPacket(DeviceObject
, FALSE
);
2709 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2710 srb
->DataBuffer
= dataBuffer
;
2712 RtlZeroMemory(dataBuffer
, MODE_DATA_SIZE
);
2716 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
2717 cdb
->MODE_SENSE
.PageCode
= CDROM_AUDIO_CONTROL_PAGE
;
2718 cdb
->MODE_SENSE
.AllocationLength
= MODE_DATA_SIZE
;
2724 cdb
->MODE_SENSE10
.OperationCode
= SCSIOP_MODE_SENSE10
;
2725 cdb
->MODE_SENSE10
.PageCode
= CDROM_AUDIO_CONTROL_PAGE
;
2726 cdb
->MODE_SENSE10
.AllocationLength
[0] = (UCHAR
)(MODE_DATA_SIZE
>> 8);
2727 cdb
->MODE_SENSE10
.AllocationLength
[1] = (UCHAR
)(MODE_DATA_SIZE
& 0xFF);
2729 srb
->CdbLength
= 10;
2732 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2733 srb
->DataTransferLength
= MODE_DATA_SIZE
;
2734 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2735 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
2737 if (currentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_SET_VOLUME
) {
2740 // Setup a different completion routine as the mode sense data is needed in order
2741 // to send the mode select.
2744 IoSetCompletionRoutine(irp2
,
2745 CdRomSetVolumeIntermediateCompletion
,
2753 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2761 // Just complete the request - CdRomClassIoctlCompletion will take
2762 // care of it for us
2765 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2772 // If a read or an unhandled IRP_MJ_XX, end up here. The unhandled IRP_MJ's
2773 // are expected and composed of AutoRun Irps, at present.
2776 IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
2783 ScsiCdRomReadVerification(
2784 IN PDEVICE_OBJECT DeviceObject
,
2790 Routine Description:
2792 This is the entry called by the I/O system for read requests.
2793 It builds the SRB and sends it to the port driver.
2797 DeviceObject - the system object for the device.
2807 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2808 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
2809 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
2810 LARGE_INTEGER startingOffset
= currentIrpStack
->Parameters
.Read
.ByteOffset
;
2813 // If the cd is playing music then reject this request.
2816 if (PLAY_ACTIVE(deviceExtension
)) {
2817 Irp
->IoStatus
.Status
= STATUS_DEVICE_BUSY
;
2818 return STATUS_DEVICE_BUSY
;
2822 // Verify parameters of this request.
2823 // Check that ending sector is on disc and
2824 // that number of bytes to transfer is a multiple of
2828 startingOffset
.QuadPart
= currentIrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+
2831 if (!deviceExtension
->DiskGeometry
->BytesPerSector
) {
2832 deviceExtension
->DiskGeometry
->BytesPerSector
= 2048;
2835 if ((startingOffset
.QuadPart
> deviceExtension
->PartitionLength
.QuadPart
) ||
2836 (transferByteCount
& (deviceExtension
->DiskGeometry
->BytesPerSector
- 1))) {
2838 DebugPrint((1,"ScsiCdRomRead: Invalid I/O parameters\n"));
2839 DebugPrint((1, "\toffset %x:%x, Length %x:%x\n",
2840 startingOffset
.u
.HighPart
,
2841 startingOffset
.u
.LowPart
,
2842 deviceExtension
->PartitionLength
.u
.HighPart
,
2843 deviceExtension
->PartitionLength
.u
.LowPart
));
2844 DebugPrint((1, "\tbps %x\n", deviceExtension
->DiskGeometry
->BytesPerSector
));
2847 // Fail request with status of invalid parameters.
2850 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
2852 return STATUS_INVALID_PARAMETER
;
2856 return STATUS_SUCCESS
;
2858 } // end ScsiCdRomReadVerification()
2863 CdRomDeviceControlCompletion(
2864 IN PDEVICE_OBJECT DeviceObject
,
2869 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2870 PDEVICE_EXTENSION physicalExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
2871 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
2872 PCDROM_DATA cdData
= (PCDROM_DATA
)(deviceExtension
+ 1);
2873 BOOLEAN use6Byte
= cdData
->XAFlags
& XA_USE_6_BYTE
;
2874 PIO_STACK_LOCATION realIrpStack
;
2875 PIO_STACK_LOCATION realIrpNextStack
;
2876 PSCSI_REQUEST_BLOCK srb
= Context
;
2877 PIRP realIrp
= NULL
;
2882 // Extract the 'real' irp from the irpstack.
2885 realIrp
= (PIRP
) irpStack
->Parameters
.Others
.Argument2
;
2886 realIrpStack
= IoGetCurrentIrpStackLocation(realIrp
);
2887 realIrpNextStack
= IoGetNextIrpStackLocation(realIrp
);
2890 // Check SRB status for success of completing request.
2893 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
2896 "CdRomDeviceControlCompletion: Irp %lx, Srb %lx Real Irp %lx Status %lx\n",
2903 // Release the queue if it is frozen.
2906 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
2907 DebugPrint((2, "CdRomDeviceControlCompletion: Releasing Queue\n"));
2908 ScsiClassReleaseQueue(DeviceObject
);
2912 retry
= ScsiClassInterpretSenseInfo(DeviceObject
,
2914 irpStack
->MajorFunction
,
2915 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
,
2916 MAXIMUM_RETRIES
- ((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
),
2919 DebugPrint((2, "CdRomDeviceControlCompletion: IRP will %sbe retried\n",
2920 (retry
? "" : "not ")));
2923 // Some of the Device Controls need special cases on non-Success status's.
2926 if (realIrpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
) {
2927 if ((realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_GET_LAST_SESSION
) ||
2928 (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_READ_TOC
) ||
2929 (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_GET_CONTROL
) ||
2930 (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_GET_VOLUME
)) {
2932 if (status
== STATUS_DATA_OVERRUN
) {
2933 status
= STATUS_SUCCESS
;
2938 if (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_READ_Q_CHANNEL
) {
2939 PLAY_ACTIVE(deviceExtension
) = FALSE
;
2944 // If the status is verified required and the this request
2945 // should bypass verify required then retry the request.
2948 if (realIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
2949 status
== STATUS_VERIFY_REQUIRED
) {
2951 if (((realIrpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
) ||
2952 (realIrpStack
->MajorFunction
== IRP_MJ_INTERNAL_DEVICE_CONTROL
)) &&
2953 (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_CHECK_VERIFY
)) {
2956 // Update the geometry information, as the media could have changed.
2957 // The completion routine for this will complete the real irp and start
2961 status
= CdRomUpdateCapacity(deviceExtension
,realIrp
, NULL
);
2962 DebugPrint((2, "CdRomDeviceControlCompletion: [%lx] CdRomUpdateCapacity completed with status %lx\n", realIrp
, status
));
2963 ASSERT(status
== STATUS_PENDING
);
2965 return STATUS_MORE_PROCESSING_REQUIRED
;
2969 status
= STATUS_IO_DEVICE_ERROR
;
2975 if (retry
&& (realIrpNextStack
->Parameters
.Others
.Argument1
= (PVOID
)((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
-1))) {
2977 if (((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
)) {
2983 DebugPrint((1, "Retry request %lx - Calling StartIo\n", Irp
));
2986 ExFreePool(srb
->SenseInfoBuffer
);
2987 if (srb
->DataBuffer
) {
2988 ExFreePool(srb
->DataBuffer
);
2991 if (Irp
->MdlAddress
) {
2992 IoFreeMdl(Irp
->MdlAddress
);
2998 // Call StartIo directly since IoStartNextPacket hasn't been called,
2999 // the serialisation is still intact.
3002 ScsiCdRomStartIo(DeviceObject
, realIrp
);
3003 return STATUS_MORE_PROCESSING_REQUIRED
;
3008 // Exhausted retries. Fall through and complete the request with the appropriate status.
3015 // Set status for successful request.
3018 status
= STATUS_SUCCESS
;
3021 if (NT_SUCCESS(status
)) {
3023 switch (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
) {
3025 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
: {
3027 PREAD_CAPACITY_DATA readCapacityBuffer
= srb
->DataBuffer
;
3034 // Swizzle bytes from Read Capacity and translate into
3035 // the necessary geometry information in the device extension.
3038 tmp
= readCapacityBuffer
->BytesPerBlock
;
3039 ((PFOUR_BYTE
)&bps
)->Byte0
= ((PFOUR_BYTE
)&tmp
)->Byte3
;
3040 ((PFOUR_BYTE
)&bps
)->Byte1
= ((PFOUR_BYTE
)&tmp
)->Byte2
;
3041 ((PFOUR_BYTE
)&bps
)->Byte2
= ((PFOUR_BYTE
)&tmp
)->Byte1
;
3042 ((PFOUR_BYTE
)&bps
)->Byte3
= ((PFOUR_BYTE
)&tmp
)->Byte0
;
3045 // Insure that bps is a power of 2.
3046 // This corrects a problem with the HP 4020i CDR where it
3047 // returns an incorrect number for bytes per sector.
3053 lastBit
= (ULONG
) -1;
3061 deviceExtension
->DiskGeometry
->BytesPerSector
= bps
;
3064 "CdRomDeviceControlCompletion: Calculated bps %#x\n",
3065 deviceExtension
->DiskGeometry
->BytesPerSector
));
3068 // Copy last sector in reverse byte order.
3071 tmp
= readCapacityBuffer
->LogicalBlockAddress
;
3072 ((PFOUR_BYTE
)&lastSector
)->Byte0
= ((PFOUR_BYTE
)&tmp
)->Byte3
;
3073 ((PFOUR_BYTE
)&lastSector
)->Byte1
= ((PFOUR_BYTE
)&tmp
)->Byte2
;
3074 ((PFOUR_BYTE
)&lastSector
)->Byte2
= ((PFOUR_BYTE
)&tmp
)->Byte1
;
3075 ((PFOUR_BYTE
)&lastSector
)->Byte3
= ((PFOUR_BYTE
)&tmp
)->Byte0
;
3078 // Calculate sector to byte shift.
3081 WHICH_BIT(bps
, deviceExtension
->SectorShift
);
3083 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Sector size is %d\n",
3084 deviceExtension
->DiskGeometry
->BytesPerSector
));
3086 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Number of Sectors is %d\n",
3090 // Calculate media capacity in bytes.
3093 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(lastSector
+ 1);
3096 // Calculate number of cylinders.
3099 deviceExtension
->DiskGeometry
->Cylinders
.QuadPart
= (LONGLONG
)((lastSector
+ 1)/(32 * 64));
3101 deviceExtension
->PartitionLength
.QuadPart
=
3102 (deviceExtension
->PartitionLength
.QuadPart
<< deviceExtension
->SectorShift
);
3104 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
3107 // This device supports removable media.
3110 deviceExtension
->DiskGeometry
->MediaType
= RemovableMedia
;
3115 // Assume media type is fixed disk.
3118 deviceExtension
->DiskGeometry
->MediaType
= FixedMedia
;
3122 // Assume sectors per track are 32;
3125 deviceExtension
->DiskGeometry
->SectorsPerTrack
= 32;
3128 // Assume tracks per cylinder (number of heads) is 64.
3131 deviceExtension
->DiskGeometry
->TracksPerCylinder
= 64;
3134 // Copy the device extension's geometry info into the user buffer.
3137 RtlMoveMemory(realIrp
->AssociatedIrp
.SystemBuffer
,
3138 deviceExtension
->DiskGeometry
,
3139 sizeof(DISK_GEOMETRY
));
3142 // update information field.
3145 realIrp
->IoStatus
.Information
= sizeof(DISK_GEOMETRY
);
3149 case IOCTL_CDROM_CHECK_VERIFY
:
3151 if((realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_CHECK_VERIFY
) &&
3152 (realIrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
)) {
3154 *((PULONG
)realIrp
->AssociatedIrp
.SystemBuffer
) =
3155 physicalExtension
->MediaChangeCount
;
3156 realIrp
->IoStatus
.Information
= sizeof(ULONG
);
3158 realIrp
->IoStatus
.Information
= 0;
3161 DebugPrint((2, "CdRomDeviceControlCompletion: [%lx] completing CHECK_VERIFY buddy irp %lx\n", realIrp
, Irp
));
3164 case IOCTL_CDROM_GET_LAST_SESSION
:
3165 case IOCTL_CDROM_READ_TOC
: {
3167 PCDROM_TOC toc
= srb
->DataBuffer
;
3170 // Copy the device extension's geometry info into the user buffer.
3173 RtlMoveMemory(realIrp
->AssociatedIrp
.SystemBuffer
,
3175 srb
->DataTransferLength
);
3178 // update information field.
3181 realIrp
->IoStatus
.Information
= srb
->DataTransferLength
;
3185 case IOCTL_CDROM_PLAY_AUDIO_MSF
:
3187 PLAY_ACTIVE(deviceExtension
) = TRUE
;
3191 case IOCTL_CDROM_READ_Q_CHANNEL
: {
3193 PSUB_Q_CHANNEL_DATA userChannelData
= realIrp
->AssociatedIrp
.SystemBuffer
;
3195 PCDROM_SUB_Q_DATA_FORMAT inputBuffer
= realIrp
->AssociatedIrp
.SystemBuffer
;
3197 PSUB_Q_CHANNEL_DATA subQPtr
= srb
->DataBuffer
;
3200 switch( inputBuffer
->Format
) {
3202 case IOCTL_CDROM_CURRENT_POSITION
:
3203 DebugPrint((2,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr
->CurrentPosition
.Header
.AudioStatus
));
3204 DebugPrint((2,"CdRomDeviceControlCompletion: ADR = 0x%x\n", subQPtr
->CurrentPosition
.ADR
));
3205 DebugPrint((2,"CdRomDeviceControlCompletion: Control = 0x%x\n", subQPtr
->CurrentPosition
.Control
));
3206 DebugPrint((2,"CdRomDeviceControlCompletion: Track = %u\n", subQPtr
->CurrentPosition
.TrackNumber
));
3207 DebugPrint((2,"CdRomDeviceControlCompletion: Index = %u\n", subQPtr
->CurrentPosition
.IndexNumber
));
3208 DebugPrint((2,"CdRomDeviceControlCompletion: Absolute Address = %x\n", *((PULONG
)subQPtr
->CurrentPosition
.AbsoluteAddress
) ));
3209 DebugPrint((2,"CdRomDeviceControlCompletion: Relative Address = %x\n", *((PULONG
)subQPtr
->CurrentPosition
.TrackRelativeAddress
) ));
3212 case IOCTL_CDROM_MEDIA_CATALOG
:
3213 DebugPrint((2,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr
->MediaCatalog
.Header
.AudioStatus
));
3214 DebugPrint((2,"CdRomDeviceControlCompletion: Mcval is %u\n", subQPtr
->MediaCatalog
.Mcval
));
3217 case IOCTL_CDROM_TRACK_ISRC
:
3218 DebugPrint((2,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr
->TrackIsrc
.Header
.AudioStatus
));
3219 DebugPrint((2,"CdRomDeviceControlCompletion: Tcval is %u\n", subQPtr
->TrackIsrc
.Tcval
));
3226 // Update the play active status.
3229 if (subQPtr
->CurrentPosition
.Header
.AudioStatus
== AUDIO_STATUS_IN_PROGRESS
) {
3231 PLAY_ACTIVE(deviceExtension
) = TRUE
;
3235 PLAY_ACTIVE(deviceExtension
) = FALSE
;
3240 // Check if output buffer is large enough to contain
3244 if (realIrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
3245 srb
->DataTransferLength
) {
3247 srb
->DataTransferLength
=
3248 realIrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
3252 // Copy our buffer into users.
3255 RtlMoveMemory(userChannelData
,
3257 srb
->DataTransferLength
);
3259 realIrp
->IoStatus
.Information
= srb
->DataTransferLength
;
3263 case IOCTL_CDROM_PAUSE_AUDIO
:
3265 PLAY_ACTIVE(deviceExtension
) = FALSE
;
3266 realIrp
->IoStatus
.Information
= 0;
3269 case IOCTL_CDROM_RESUME_AUDIO
:
3271 realIrp
->IoStatus
.Information
= 0;
3274 case IOCTL_CDROM_SEEK_AUDIO_MSF
:
3276 realIrp
->IoStatus
.Information
= 0;
3279 case IOCTL_CDROM_STOP_AUDIO
:
3281 PLAY_ACTIVE(deviceExtension
) = FALSE
;
3283 realIrp
->IoStatus
.Information
= 0;
3286 case IOCTL_CDROM_GET_CONTROL
: {
3288 PCDROM_AUDIO_CONTROL audioControl
= srb
->DataBuffer
;
3289 PAUDIO_OUTPUT audioOutput
;
3290 ULONG bytesTransferred
;
3292 audioOutput
= ScsiClassFindModePage((PCHAR
)audioControl
,
3293 srb
->DataTransferLength
,
3294 CDROM_AUDIO_CONTROL_PAGE
,
3297 // Verify the page is as big as expected.
3300 bytesTransferred
= (PCHAR
) audioOutput
- (PCHAR
) audioControl
+
3301 sizeof(AUDIO_OUTPUT
);
3303 if (audioOutput
!= NULL
&&
3304 srb
->DataTransferLength
>= bytesTransferred
) {
3306 audioControl
->LbaFormat
= audioOutput
->LbaFormat
;
3308 audioControl
->LogicalBlocksPerSecond
=
3309 (audioOutput
->LogicalBlocksPerSecond
[0] << (UCHAR
)8) |
3310 audioOutput
->LogicalBlocksPerSecond
[1];
3312 realIrp
->IoStatus
.Information
= sizeof(CDROM_AUDIO_CONTROL
);
3315 realIrp
->IoStatus
.Information
= 0;
3316 status
= STATUS_INVALID_DEVICE_REQUEST
;
3321 case IOCTL_CDROM_GET_VOLUME
: {
3323 PAUDIO_OUTPUT audioOutput
;
3324 PVOLUME_CONTROL volumeControl
= srb
->DataBuffer
;
3325 ULONG i
,bytesTransferred
;
3327 audioOutput
= ScsiClassFindModePage((PCHAR
)volumeControl
,
3328 srb
->DataTransferLength
,
3329 CDROM_AUDIO_CONTROL_PAGE
,
3333 // Verify the page is as big as expected.
3336 bytesTransferred
= (PCHAR
) audioOutput
- (PCHAR
) volumeControl
+
3337 sizeof(AUDIO_OUTPUT
);
3339 if (audioOutput
!= NULL
&&
3340 srb
->DataTransferLength
>= bytesTransferred
) {
3342 for (i
=0; i
<4; i
++) {
3343 volumeControl
->PortVolume
[i
] =
3344 audioOutput
->PortOutput
[i
].Volume
;
3348 // Set bytes transferred in IRP.
3351 realIrp
->IoStatus
.Information
= sizeof(VOLUME_CONTROL
);
3354 realIrp
->IoStatus
.Information
= 0;
3355 status
= STATUS_INVALID_DEVICE_REQUEST
;
3361 case IOCTL_CDROM_SET_VOLUME
:
3363 realIrp
->IoStatus
.Information
= sizeof(VOLUME_CONTROL
);
3369 realIrp
->IoStatus
.Information
= 0;
3370 status
= STATUS_INVALID_DEVICE_REQUEST
;
3376 // Deallocate srb and sense buffer.
3380 if (srb
->DataBuffer
) {
3381 ExFreePool(srb
->DataBuffer
);
3383 if (srb
->SenseInfoBuffer
) {
3384 ExFreePool(srb
->SenseInfoBuffer
);
3389 if (realIrp
->PendingReturned
) {
3390 IoMarkIrpPending(realIrp
);
3393 if (Irp
->MdlAddress
) {
3394 IoFreeMdl(Irp
->MdlAddress
);
3400 // Set status in completing IRP.
3403 realIrp
->IoStatus
.Status
= status
;
3406 // Set the hard error if necessary.
3409 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
3412 // Store DeviceObject for filesystem, and clear
3413 // in IoStatus.Information field.
3416 DebugPrint((1, "CdRomDeviceCompletion - Setting Hard Error on realIrp %lx\n",
3418 IoSetHardErrorOrVerifyDevice(realIrp
, DeviceObject
);
3419 realIrp
->IoStatus
.Information
= 0;
3422 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
3424 IoStartNextPacket(DeviceObject
, FALSE
);
3426 return STATUS_MORE_PROCESSING_REQUIRED
;
3431 CdRomSetVolumeIntermediateCompletion(
3432 IN PDEVICE_OBJECT DeviceObject
,
3437 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3438 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3439 PCDROM_DATA cdData
= (PCDROM_DATA
)(deviceExtension
+ 1);
3440 BOOLEAN use6Byte
= cdData
->XAFlags
& XA_USE_6_BYTE
;
3441 PIO_STACK_LOCATION realIrpStack
;
3442 PIO_STACK_LOCATION realIrpNextStack
;
3443 PSCSI_REQUEST_BLOCK srb
= Context
;
3444 PIRP realIrp
= NULL
;
3449 // Extract the 'real' irp from the irpstack.
3452 realIrp
= (PIRP
) irpStack
->Parameters
.Others
.Argument2
;
3453 realIrpStack
= IoGetCurrentIrpStackLocation(realIrp
);
3454 realIrpNextStack
= IoGetNextIrpStackLocation(realIrp
);
3457 // Check SRB status for success of completing request.
3460 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
3463 "CdRomSetVolumeIntermediateCompletion: Irp %lx, Srb %lx Real Irp\n",
3469 // Release the queue if it is frozen.
3472 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
3473 ScsiClassReleaseQueue(DeviceObject
);
3477 retry
= ScsiClassInterpretSenseInfo(DeviceObject
,
3479 irpStack
->MajorFunction
,
3480 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
,
3481 MAXIMUM_RETRIES
- ((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
),
3484 if (status
== STATUS_DATA_OVERRUN
) {
3485 status
= STATUS_SUCCESS
;
3490 // If the status is verified required and the this request
3491 // should bypass verify required then retry the request.
3494 if (realIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
3495 status
== STATUS_VERIFY_REQUIRED
) {
3497 status
= STATUS_IO_DEVICE_ERROR
;
3501 if (retry
&& (realIrpNextStack
->Parameters
.Others
.Argument1
= (PVOID
)((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
-1))) {
3503 if (((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
)) {
3509 DebugPrint((1, "Retry request %lx - Calling StartIo\n", Irp
));
3512 ExFreePool(srb
->SenseInfoBuffer
);
3513 ExFreePool(srb
->DataBuffer
);
3515 if (Irp
->MdlAddress
) {
3516 IoFreeMdl(Irp
->MdlAddress
);
3522 // Call StartIo directly since IoStartNextPacket hasn't been called,
3523 // the serialisation is still intact.
3525 ScsiCdRomStartIo(DeviceObject
, realIrp
);
3526 return STATUS_MORE_PROCESSING_REQUIRED
;
3531 // Exhausted retries. Fall through and complete the request with the appropriate status.
3538 // Set status for successful request.
3541 status
= STATUS_SUCCESS
;
3544 if (NT_SUCCESS(status
)) {
3546 PAUDIO_OUTPUT audioInput
= NULL
;
3547 PAUDIO_OUTPUT audioOutput
;
3548 PVOLUME_CONTROL volumeControl
= realIrp
->AssociatedIrp
.SystemBuffer
;
3549 ULONG i
,bytesTransferred
,headerLength
;
3553 audioInput
= ScsiClassFindModePage((PCHAR
)srb
->DataBuffer
,
3554 srb
->DataTransferLength
,
3555 CDROM_AUDIO_CONTROL_PAGE
,
3559 // Check to make sure the mode sense data is valid before we go on
3562 if(audioInput
== NULL
) {
3564 DebugPrint((1, "Mode Sense Page %d not found\n",
3565 CDROM_AUDIO_CONTROL_PAGE
));
3567 realIrp
->IoStatus
.Information
= 0;
3568 realIrp
->IoStatus
.Status
= STATUS_IO_DEVICE_ERROR
;
3569 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
3570 ExFreePool(srb
->SenseInfoBuffer
);
3572 IoFreeMdl(Irp
->MdlAddress
);
3574 return STATUS_MORE_PROCESSING_REQUIRED
;
3578 headerLength
= sizeof(MODE_PARAMETER_HEADER
);
3580 headerLength
= sizeof(MODE_PARAMETER_HEADER10
);
3583 bytesTransferred
= sizeof(AUDIO_OUTPUT
) + headerLength
;
3586 // Allocate a new buffer for the mode select.
3589 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, bytesTransferred
);
3592 realIrp
->IoStatus
.Information
= 0;
3593 realIrp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3594 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
3595 ExFreePool(srb
->SenseInfoBuffer
);
3597 IoFreeMdl(Irp
->MdlAddress
);
3599 return STATUS_MORE_PROCESSING_REQUIRED
;
3602 RtlZeroMemory(dataBuffer
, bytesTransferred
);
3605 // Rebuild the data buffer to include the user requested values.
3608 audioOutput
= (PAUDIO_OUTPUT
) ((PCHAR
) dataBuffer
+ headerLength
);
3610 for (i
=0; i
<4; i
++) {
3611 audioOutput
->PortOutput
[i
].Volume
=
3612 volumeControl
->PortVolume
[i
];
3613 audioOutput
->PortOutput
[i
].ChannelSelection
=
3614 audioInput
->PortOutput
[i
].ChannelSelection
;
3617 audioOutput
->CodePage
= CDROM_AUDIO_CONTROL_PAGE
;
3618 audioOutput
->ParameterLength
= sizeof(AUDIO_OUTPUT
) - 2;
3619 audioOutput
->Immediate
= MODE_SELECT_IMMEDIATE
;
3622 // Free the old data buffer, mdl.
3625 ExFreePool(srb
->DataBuffer
);
3626 IoFreeMdl(Irp
->MdlAddress
);
3632 cdb
= (PCDB
)srb
->Cdb
;
3633 RtlZeroMemory(cdb
, CDB12GENERIC_LENGTH
);
3635 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
3636 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
3637 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_OUT
);
3638 srb
->DataTransferLength
= bytesTransferred
;
3642 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
3643 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
) bytesTransferred
;
3644 cdb
->MODE_SELECT
.PFBit
= 1;
3648 cdb
->MODE_SELECT10
.OperationCode
= SCSIOP_MODE_SELECT10
;
3649 cdb
->MODE_SELECT10
.ParameterListLength
[0] = (UCHAR
) (bytesTransferred
>> 8);
3650 cdb
->MODE_SELECT10
.ParameterListLength
[1] = (UCHAR
) (bytesTransferred
& 0xFF);
3651 cdb
->MODE_SELECT10
.PFBit
= 1;
3652 srb
->CdbLength
= 10;
3659 Irp
->MdlAddress
= IoAllocateMdl(dataBuffer
,
3665 if (!Irp
->MdlAddress
) {
3666 realIrp
->IoStatus
.Information
= 0;
3667 realIrp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3668 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
3669 ExFreePool(srb
->SenseInfoBuffer
);
3671 ExFreePool(dataBuffer
);
3673 return STATUS_MORE_PROCESSING_REQUIRED
;
3677 MmBuildMdlForNonPagedPool(Irp
->MdlAddress
);
3678 srb
->DataBuffer
= dataBuffer
;
3680 irpStack
= IoGetNextIrpStackLocation(Irp
);
3681 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
3682 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
3683 irpStack
->Parameters
.Scsi
.Srb
= srb
;
3686 // reset the irp completion.
3689 IoSetCompletionRoutine(Irp
,
3690 CdRomDeviceControlCompletion
,
3696 // Call the port driver.
3699 IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
3701 return STATUS_MORE_PROCESSING_REQUIRED
;
3705 // Deallocate srb and sense buffer.
3709 if (srb
->DataBuffer
) {
3710 ExFreePool(srb
->DataBuffer
);
3712 if (srb
->SenseInfoBuffer
) {
3713 ExFreePool(srb
->SenseInfoBuffer
);
3718 if (Irp
->PendingReturned
) {
3719 IoMarkIrpPending(Irp
);
3722 if (realIrp
->PendingReturned
) {
3723 IoMarkIrpPending(realIrp
);
3726 if (Irp
->MdlAddress
) {
3727 IoFreeMdl(Irp
->MdlAddress
);
3733 // Set status in completing IRP.
3736 realIrp
->IoStatus
.Status
= status
;
3739 // Set the hard error if necessary.
3742 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
3745 // Store DeviceObject for filesystem, and clear
3746 // in IoStatus.Information field.
3749 IoSetHardErrorOrVerifyDevice(realIrp
, DeviceObject
);
3750 realIrp
->IoStatus
.Information
= 0;
3753 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
3755 IoStartNextPacket(DeviceObject
, FALSE
);
3757 return STATUS_MORE_PROCESSING_REQUIRED
;
3763 CdRomSwitchModeCompletion(
3764 IN PDEVICE_OBJECT DeviceObject
,
3769 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3770 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3771 PCDROM_DATA cdData
= (PCDROM_DATA
)(deviceExtension
+ 1);
3772 PIO_STACK_LOCATION realIrpStack
;
3773 PIO_STACK_LOCATION realIrpNextStack
;
3774 PSCSI_REQUEST_BLOCK srb
= Context
;
3775 PIRP realIrp
= NULL
;
3780 // Extract the 'real' irp from the irpstack.
3783 realIrp
= (PIRP
) irpStack
->Parameters
.Others
.Argument2
;
3784 realIrpStack
= IoGetCurrentIrpStackLocation(realIrp
);
3785 realIrpNextStack
= IoGetNextIrpStackLocation(realIrp
);
3788 // Check SRB status for success of completing request.
3791 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
3794 "CdRomSetVolumeIntermediateCompletion: Irp %lx, Srb %lx Real Irp\n",
3800 // Release the queue if it is frozen.
3803 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
3804 ScsiClassReleaseQueue(DeviceObject
);
3808 retry
= ScsiClassInterpretSenseInfo(DeviceObject
,
3810 irpStack
->MajorFunction
,
3811 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
,
3812 MAXIMUM_RETRIES
- ((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
),
3816 // If the status is verified required and the this request
3817 // should bypass verify required then retry the request.
3820 if (realIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
3821 status
== STATUS_VERIFY_REQUIRED
) {
3823 status
= STATUS_IO_DEVICE_ERROR
;
3827 if (retry
&& (realIrpNextStack
->Parameters
.Others
.Argument1
= (PVOID
)((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
-1))) {
3829 if (((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
)) {
3835 DebugPrint((1, "Retry request %lx - Calling StartIo\n", Irp
));
3838 ExFreePool(srb
->SenseInfoBuffer
);
3839 ExFreePool(srb
->DataBuffer
);
3841 if (Irp
->MdlAddress
) {
3842 IoFreeMdl(Irp
->MdlAddress
);
3848 // Call StartIo directly since IoStartNextPacket hasn't been called,
3849 // the serialisation is still intact.
3852 ScsiCdRomStartIo(DeviceObject
, realIrp
);
3853 return STATUS_MORE_PROCESSING_REQUIRED
;
3858 // Exhausted retries. Fall through and complete the request with the appropriate status.
3864 // Set status for successful request.
3867 status
= STATUS_SUCCESS
;
3870 if (NT_SUCCESS(status
)) {
3872 ULONG sectorSize
, startingSector
, transferByteCount
;
3876 // Update device ext. to show which mode we are currently using.
3879 sectorSize
= cdData
->u1
.BlockDescriptor
.BlockLength
[0] << 16;
3880 sectorSize
|= (cdData
->u1
.BlockDescriptor
.BlockLength
[1] << 8);
3881 sectorSize
|= (cdData
->u1
.BlockDescriptor
.BlockLength
[2]);
3883 cdData
->RawAccess
= (sectorSize
== RAW_SECTOR_SIZE
) ? TRUE
: FALSE
;
3886 // Free the old data buffer, mdl.
3889 ExFreePool(srb
->DataBuffer
);
3890 IoFreeMdl(Irp
->MdlAddress
);
3897 cdb
= (PCDB
)srb
->Cdb
;
3898 RtlZeroMemory(cdb
, CDB12GENERIC_LENGTH
);
3901 if (cdData
->RawAccess
) {
3903 PRAW_READ_INFO rawReadInfo
=
3904 (PRAW_READ_INFO
)realIrpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
3906 ULONG maximumTransferLength
;
3907 ULONG transferPages
;
3910 // Calculate starting offset.
3913 startingSector
= (ULONG
)(rawReadInfo
->DiskOffset
.QuadPart
>> deviceExtension
->SectorShift
);
3914 transferByteCount
= rawReadInfo
->SectorCount
* RAW_SECTOR_SIZE
;
3915 maximumTransferLength
= deviceExtension
->PortCapabilities
->MaximumTransferLength
;
3916 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(realIrp
->MdlAddress
),
3920 // Determine if request is within limits imposed by miniport.
3921 // If the request is larger than the miniport's capabilities, split it.
3924 if (transferByteCount
> maximumTransferLength
||
3925 transferPages
> deviceExtension
->PortCapabilities
->MaximumPhysicalPages
) {
3927 realIrp
->IoStatus
.Information
= 0;
3928 realIrp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
3929 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
3931 ExFreePool(srb
->SenseInfoBuffer
);
3932 ExFreePool(srb
->DataBuffer
);
3934 IoFreeMdl(Irp
->MdlAddress
);
3937 IoStartNextPacket(DeviceObject
, FALSE
);
3939 return STATUS_MORE_PROCESSING_REQUIRED
;
3942 srb
->OriginalRequest
= realIrp
;
3943 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
3944 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
3945 srb
->DataTransferLength
= transferByteCount
;
3946 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
3947 srb
->CdbLength
= 10;
3948 srb
->DataBuffer
= MmGetMdlVirtualAddress(realIrp
->MdlAddress
);
3950 if (rawReadInfo
->TrackMode
== CDDA
) {
3951 if (cdData
->XAFlags
& PLEXTOR_CDDA
) {
3953 srb
->CdbLength
= 12;
3955 cdb
->PLXTR_READ_CDDA
.LogicalUnitNumber
= deviceExtension
->Lun
;
3956 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
3957 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
3958 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
3959 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
3961 cdb
->PLXTR_READ_CDDA
.TransferBlockByte3
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
3962 cdb
->PLXTR_READ_CDDA
.TransferBlockByte2
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
3963 cdb
->PLXTR_READ_CDDA
.TransferBlockByte1
= 0;
3964 cdb
->PLXTR_READ_CDDA
.TransferBlockByte0
= 0;
3966 cdb
->PLXTR_READ_CDDA
.SubCode
= 0;
3967 cdb
->PLXTR_READ_CDDA
.OperationCode
= 0xD8;
3969 } else if (cdData
->XAFlags
& NEC_CDDA
) {
3971 cdb
->NEC_READ_CDDA
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
3972 cdb
->NEC_READ_CDDA
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
3973 cdb
->NEC_READ_CDDA
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
3974 cdb
->NEC_READ_CDDA
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
3976 cdb
->NEC_READ_CDDA
.TransferBlockByte1
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
3977 cdb
->NEC_READ_CDDA
.TransferBlockByte0
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
3979 cdb
->NEC_READ_CDDA
.OperationCode
= 0xD4;
3982 cdb
->CDB10
.LogicalUnitNumber
= deviceExtension
->Lun
;
3984 cdb
->CDB10
.TransferBlocksMsb
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
3985 cdb
->CDB10
.TransferBlocksLsb
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
3987 cdb
->CDB10
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
3988 cdb
->CDB10
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
3989 cdb
->CDB10
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
3990 cdb
->CDB10
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
3992 cdb
->CDB10
.OperationCode
= SCSIOP_READ
;
3995 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
3998 irpStack
= IoGetNextIrpStackLocation(realIrp
);
3999 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
4000 irpStack
->Parameters
.Scsi
.Srb
= srb
;
4002 if (!(irpStack
->Parameters
.Others
.Argument1
)) {
4005 // Only jam this in if it doesn't exist. The completion routines can
4006 // call StartIo directly in the case of retries and resetting it will
4007 // cause infinite loops.
4010 irpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
4014 // Set up IoCompletion routine address.
4017 IoSetCompletionRoutine(realIrp
,
4025 ULONG maximumTransferLength
= deviceExtension
->PortCapabilities
->MaximumTransferLength
;
4026 ULONG transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(realIrp
->MdlAddress
),
4027 realIrpStack
->Parameters
.Read
.Length
);
4029 // Back to cooked sectors. Build and send a normal read.
4030 // The real work for setting offsets and checking for splitrequests was
4034 if ((realIrpStack
->Parameters
.Read
.Length
> maximumTransferLength
) ||
4035 (transferPages
> deviceExtension
->PortCapabilities
->MaximumPhysicalPages
)) {
4038 // Request needs to be split. Completion of each portion of the request will
4039 // fire off the next portion. The final request will signal Io to send a new request.
4042 ScsiClassSplitRequest(DeviceObject
, realIrp
, maximumTransferLength
);
4043 return STATUS_MORE_PROCESSING_REQUIRED
;
4048 // Build SRB and CDB for this IRP.
4051 ScsiClassBuildRequest(DeviceObject
, realIrp
);
4057 // Call the port driver.
4060 IoCallDriver(deviceExtension
->PortDeviceObject
, realIrp
);
4062 return STATUS_MORE_PROCESSING_REQUIRED
;
4066 // Update device Extension flags to indicate that XA isn't supported.
4069 cdData
->XAFlags
|= XA_NOT_SUPPORTED
;
4072 // Deallocate srb and sense buffer.
4076 if (srb
->DataBuffer
) {
4077 ExFreePool(srb
->DataBuffer
);
4079 if (srb
->SenseInfoBuffer
) {
4080 ExFreePool(srb
->SenseInfoBuffer
);
4085 if (Irp
->PendingReturned
) {
4086 IoMarkIrpPending(Irp
);
4089 if (realIrp
->PendingReturned
) {
4090 IoMarkIrpPending(realIrp
);
4093 if (Irp
->MdlAddress
) {
4094 IoFreeMdl(Irp
->MdlAddress
);
4100 // Set status in completing IRP.
4103 realIrp
->IoStatus
.Status
= status
;
4106 // Set the hard error if necessary.
4109 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
4112 // Store DeviceObject for filesystem, and clear
4113 // in IoStatus.Information field.
4116 IoSetHardErrorOrVerifyDevice(realIrp
, DeviceObject
);
4117 realIrp
->IoStatus
.Information
= 0;
4120 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
4122 IoStartNextPacket(DeviceObject
, FALSE
);
4124 return STATUS_MORE_PROCESSING_REQUIRED
;
4130 IN PDEVICE_OBJECT DeviceObject
,
4137 Routine Description:
4139 This routine executes when the port driver has completed a request.
4140 It looks at the SRB status in the completing SRB and if not success
4141 it checks for valid request sense buffer information. If valid, the
4142 info is used to update status with more precise message of type of
4143 error. This routine deallocates the SRB.
4147 DeviceObject - Supplies the device object which represents the logical
4150 Irp - Supplies the Irp which has completed.
4152 Context - Supplies a pointer to the SRB.
4161 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
4162 PIO_STACK_LOCATION irpNextStack
= IoGetNextIrpStackLocation(Irp
);
4163 PSCSI_REQUEST_BLOCK srb
= Context
;
4168 // Check SRB status for success of completing request.
4171 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
4173 DebugPrint((2,"ScsiClassIoComplete: IRP %lx, SRB %lx\n", Irp
, srb
));
4176 // Release the queue if it is frozen.
4179 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
4180 ScsiClassReleaseQueue(DeviceObject
);
4183 retry
= ScsiClassInterpretSenseInfo(
4186 irpStack
->MajorFunction
,
4187 irpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
? irpStack
->Parameters
.DeviceIoControl
.IoControlCode
: 0,
4188 MAXIMUM_RETRIES
- ((ULONG_PTR
)irpNextStack
->Parameters
.Others
.Argument1
),
4192 // If the status is verified required and the this request
4193 // should bypass verify required then retry the request.
4196 if (irpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
4197 status
== STATUS_VERIFY_REQUIRED
) {
4199 status
= STATUS_IO_DEVICE_ERROR
;
4203 if (retry
&& (irpNextStack
->Parameters
.Others
.Argument1
= (PVOID
)((ULONG_PTR
)irpNextStack
->Parameters
.Others
.Argument1
-1))) {
4205 if (((ULONG_PTR
)irpNextStack
->Parameters
.Others
.Argument1
)) {
4211 DebugPrint((1, "CdRomXACompletion: Retry request %lx - Calling StartIo\n", Irp
));
4214 ExFreePool(srb
->SenseInfoBuffer
);
4215 ExFreePool(srb
->DataBuffer
);
4219 // Call StartIo directly since IoStartNextPacket hasn't been called,
4220 // the serialisation is still intact.
4223 ScsiCdRomStartIo(DeviceObject
, Irp
);
4224 return STATUS_MORE_PROCESSING_REQUIRED
;
4229 // Exhausted retries. Fall through and complete the request with the appropriate status.
4235 // Set status for successful request.
4238 status
= STATUS_SUCCESS
;
4240 } // end if (SRB_STATUS(srb->SrbStatus) ...
4243 // Return SRB to nonpaged pool.
4249 // Set status in completing IRP.
4252 Irp
->IoStatus
.Status
= status
;
4255 // Set the hard error if necessary.
4258 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
4261 // Store DeviceObject for filesystem, and clear
4262 // in IoStatus.Information field.
4265 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
4266 Irp
->IoStatus
.Information
= 0;
4270 // If pending has be returned for this irp then mark the current stack as
4274 if (Irp
->PendingReturned
) {
4275 IoMarkIrpPending(Irp
);
4278 //IoCompleteRequest(Irp, IO_DISK_INCREMENT);
4279 IoStartNextPacket(DeviceObject
, FALSE
);
4287 IN PDEVICE_OBJECT DeviceObject
,
4293 Routine Description:
4295 This is the NT device control handler for CDROMs.
4299 DeviceObject - for this CDROM
4301 Irp - IO Request packet
4310 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
4311 PIO_STACK_LOCATION nextStack
;
4312 PKEVENT deviceControlEvent
;
4313 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4314 PCDROM_DATA cdData
= (PCDROM_DATA
)(deviceExtension
+1);
4315 SCSI_REQUEST_BLOCK srb
;
4326 // Zero the SRB on stack.
4329 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
4331 Irp
->IoStatus
.Information
= 0;
4334 // if this is a class driver ioctl then we need to change the base code
4335 // to IOCTL_CDROM_BASE so that the switch statement can handle it.
4337 // WARNING - currently the scsi class ioctl function codes are between
4338 // 0x200 & 0x300. this routine depends on that fact
4341 ioctlCode
= irpStack
->Parameters
.DeviceIoControl
.IoControlCode
;
4342 baseCode
= ioctlCode
>> 16;
4343 functionCode
= (ioctlCode
& (~0xffffc003)) >> 2;
4345 DebugPrint((1, "CdRomDeviceControl: Ioctl Code = %#08lx, Base Code = %#lx,"
4346 " Function Code = %#lx\n",
4352 if((functionCode
>= 0x200) && (functionCode
<= 0x300)) {
4354 ioctlCode
= (ioctlCode
& 0x0000ffff) | CTL_CODE(IOCTL_CDROM_BASE
, 0, 0, 0);
4356 DebugPrint((1, "CdRomDeviceControl: Class Code - new ioctl code is %#08lx\n",
4359 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= ioctlCode
;
4363 switch (ioctlCode
) {
4365 case IOCTL_CDROM_RAW_READ
: {
4367 LARGE_INTEGER startingOffset
;
4368 ULONG transferBytes
;
4369 ULONG startingSector
;
4370 PRAW_READ_INFO rawReadInfo
= (PRAW_READ_INFO
)irpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
4371 PUCHAR userData
= (PUCHAR
)Irp
->AssociatedIrp
.SystemBuffer
;
4374 // Ensure that XA reads are supported.
4377 if (cdData
->XAFlags
& XA_NOT_SUPPORTED
) {
4380 "CdRomDeviceControl: XA Reads not supported. Flags (%x)\n",
4383 status
= STATUS_INVALID_DEVICE_REQUEST
;
4388 // Check that ending sector is on disc and buffers are there and of
4392 if (rawReadInfo
== NULL
) {
4395 // Called from user space. Validate the buffers.
4398 rawReadInfo
= (PRAW_READ_INFO
)userData
;
4399 irpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
= (PVOID
)userData
;
4401 if (rawReadInfo
== NULL
) {
4403 DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (No extent info\n"));
4405 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
4407 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4408 return STATUS_INVALID_PARAMETER
;
4411 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
!= sizeof(RAW_READ_INFO
)) {
4413 DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (Invalid info buffer\n"));
4415 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
4417 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4418 return STATUS_INVALID_PARAMETER
;
4422 startingOffset
.QuadPart
= rawReadInfo
->DiskOffset
.QuadPart
;
4423 startingSector
= (ULONG
)(rawReadInfo
->DiskOffset
.QuadPart
>> deviceExtension
->SectorShift
);
4424 transferBytes
= rawReadInfo
->SectorCount
* RAW_SECTOR_SIZE
;
4426 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< transferBytes
) {
4428 DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (Bad buffer size)\n"));
4431 // Fail request with status of invalid parameters.
4434 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
4436 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4437 return STATUS_INVALID_PARAMETER
;
4440 if ((startingOffset
.QuadPart
+ transferBytes
) > deviceExtension
->PartitionLength
.QuadPart
) {
4442 DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (Request Out of Bounds)\n"));
4445 // Fail request with status of invalid parameters.
4448 status
= STATUS_INVALID_PARAMETER
;
4452 IoMarkIrpPending(Irp
);
4453 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4455 return STATUS_PENDING
;
4458 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
: {
4460 DebugPrint((2,"CdRomDeviceControl: Get drive geometry\n"));
4462 if ( irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
4463 sizeof( DISK_GEOMETRY
) ) {
4465 status
= STATUS_INFO_LENGTH_MISMATCH
;
4469 IoMarkIrpPending(Irp
);
4470 IoStartPacket(DeviceObject
,Irp
, NULL
,NULL
);
4472 return STATUS_PENDING
;
4475 case IOCTL_CDROM_GET_LAST_SESSION
:
4476 case IOCTL_CDROM_READ_TOC
: {
4479 // If the cd is playing music then reject this request.
4482 if (CdRomIsPlayActive(DeviceObject
)) {
4483 Irp
->IoStatus
.Status
= STATUS_DEVICE_BUSY
;
4484 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4485 return STATUS_DEVICE_BUSY
;
4488 IoMarkIrpPending(Irp
);
4489 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4491 return STATUS_PENDING
;
4494 case IOCTL_CDROM_PLAY_AUDIO_MSF
: {
4500 DebugPrint((2,"CdRomDeviceControl: Play audio MSF\n"));
4502 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
4503 sizeof(CDROM_PLAY_AUDIO_MSF
)) {
4506 // Indicate unsuccessful status.
4509 status
= STATUS_BUFFER_TOO_SMALL
;
4513 IoMarkIrpPending(Irp
);
4514 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4516 return STATUS_PENDING
;
4519 case IOCTL_CDROM_SEEK_AUDIO_MSF
: {
4526 DebugPrint((2,"CdRomDeviceControl: Seek audio MSF\n"));
4528 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
4529 sizeof(CDROM_SEEK_AUDIO_MSF
)) {
4532 // Indicate unsuccessful status.
4535 status
= STATUS_BUFFER_TOO_SMALL
;
4538 IoMarkIrpPending(Irp
);
4539 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4541 return STATUS_PENDING
;
4546 case IOCTL_CDROM_PAUSE_AUDIO
: {
4552 DebugPrint((2, "CdRomDeviceControl: Pause audio\n"));
4554 IoMarkIrpPending(Irp
);
4555 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4557 return STATUS_PENDING
;
4562 case IOCTL_CDROM_RESUME_AUDIO
: {
4568 DebugPrint((2, "CdRomDeviceControl: Resume audio\n"));
4570 IoMarkIrpPending(Irp
);
4571 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4573 return STATUS_PENDING
;
4576 case IOCTL_CDROM_READ_Q_CHANNEL
: {
4578 if(irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
4579 sizeof(CDROM_SUB_Q_DATA_FORMAT
)) {
4581 status
= STATUS_BUFFER_TOO_SMALL
;
4582 Irp
->IoStatus
.Information
= 0;
4586 IoMarkIrpPending(Irp
);
4587 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4589 return STATUS_PENDING
;
4592 case IOCTL_CDROM_GET_CONTROL
: {
4594 DebugPrint((2, "CdRomDeviceControl: Get audio control\n"));
4597 // Verify user buffer is large enough for the data.
4600 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
4601 sizeof(CDROM_AUDIO_CONTROL
)) {
4604 // Indicate unsuccessful status and no data transferred.
4607 status
= STATUS_BUFFER_TOO_SMALL
;
4608 Irp
->IoStatus
.Information
= 0;
4613 IoMarkIrpPending(Irp
);
4614 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4616 return STATUS_PENDING
;
4620 case IOCTL_CDROM_GET_VOLUME
: {
4622 DebugPrint((2, "CdRomDeviceControl: Get volume control\n"));
4625 // Verify user buffer is large enough for data.
4628 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
4629 sizeof(VOLUME_CONTROL
)) {
4632 // Indicate unsuccessful status and no data transferred.
4635 status
= STATUS_BUFFER_TOO_SMALL
;
4636 Irp
->IoStatus
.Information
= 0;
4640 IoMarkIrpPending(Irp
);
4641 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4643 return STATUS_PENDING
;
4647 case IOCTL_CDROM_SET_VOLUME
: {
4649 DebugPrint((2, "CdRomDeviceControl: Set volume control\n"));
4651 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
4652 sizeof(VOLUME_CONTROL
)) {
4655 // Indicate unsuccessful status.
4658 status
= STATUS_BUFFER_TOO_SMALL
;
4662 IoMarkIrpPending(Irp
);
4663 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4665 return STATUS_PENDING
;
4669 case IOCTL_CDROM_STOP_AUDIO
: {
4675 DebugPrint((2, "CdRomDeviceControl: Stop audio\n"));
4677 IoMarkIrpPending(Irp
);
4678 IoStartPacket(DeviceObject
,Irp
, NULL
,NULL
);
4680 return STATUS_PENDING
;
4683 case IOCTL_CDROM_CHECK_VERIFY
: {
4684 DebugPrint((1, "CdRomDeviceControl: [%lx] Check Verify\n", Irp
));
4685 IoMarkIrpPending(Irp
);
4687 if((irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
) &&
4688 (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))) {
4690 DebugPrint((1, "CdRomDeviceControl: Check Verify: media count "
4691 "buffer too small\n"));
4693 status
= STATUS_BUFFER_TOO_SMALL
;
4697 IoStartPacket(DeviceObject
,Irp
, NULL
,NULL
);
4699 return STATUS_PENDING
;
4705 // allocate an event and stuff it into our stack location.
4708 deviceControlEvent
= ExAllocatePool(NonPagedPool
, sizeof(KEVENT
));
4710 if(!deviceControlEvent
) {
4712 status
= STATUS_INSUFFICIENT_RESOURCES
;
4716 PIO_STACK_LOCATION currentStack
;
4718 KeInitializeEvent(deviceControlEvent
, NotificationEvent
, FALSE
);
4720 currentStack
= IoGetCurrentIrpStackLocation(Irp
);
4721 nextStack
= IoGetNextIrpStackLocation(Irp
);
4724 // Copy the stack down a notch
4727 *nextStack
= *currentStack
;
4729 IoSetCompletionRoutine(
4731 CdRomClassIoctlCompletion
,
4738 IoSetNextIrpStackLocation(Irp
);
4740 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4741 Irp
->IoStatus
.Information
= 0;
4744 // Override volume verifies on this stack location so that we
4745 // will be forced through the synchronization. Once this location
4746 // goes away we get the old value back
4749 nextStack
->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
4751 IoMarkIrpPending(Irp
);
4753 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4756 // Wait for CdRomClassIoctlCompletion to set the event. This
4757 // ensures serialization remains intact for these unhandled device
4761 KeWaitForSingleObject(
4768 ExFreePool(deviceControlEvent
);
4770 DebugPrint((2, "CdRomDeviceControl: irp %#08lx synchronized\n", Irp
));
4773 // If an error occured then propagate that back up - we are no longer
4774 // guaranteed synchronization and the upper layers will have to
4777 // If no error occured, call down to the class driver directly
4778 // then start up the next request.
4781 if(Irp
->IoStatus
.Status
== STATUS_SUCCESS
) {
4783 status
= ScsiClassDeviceControl(DeviceObject
, Irp
);
4785 KeRaiseIrql(DISPATCH_LEVEL
, &irql
);
4787 IoStartNextPacket(DeviceObject
, FALSE
);
4798 if (status
== STATUS_VERIFY_REQUIRED
) {
4801 // If the status is verified required and this request
4802 // should bypass verify required then retry the request.
4805 if (irpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
) {
4807 status
= STATUS_IO_DEVICE_ERROR
;
4813 if (IoIsErrorUserInduced(status
)) {
4815 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
4820 // Update IRP with completion status.
4823 Irp
->IoStatus
.Status
= status
;
4826 // Complete the request.
4829 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
4830 DebugPrint((2, "CdRomDeviceControl: Status is %lx\n", status
));
4833 } // end ScsiCdRomDeviceControl()
4838 PDEVICE_OBJECT DeviceObject
,
4839 PINQUIRYDATA InquiryData
,
4840 PIO_SCSI_CAPABILITIES PortCapabilities
4845 Routine Description:
4847 This function checks to see if an SCSI logical unit requires an special
4848 initialization or error processing.
4852 DeviceObject - Supplies the device object to be tested.
4854 InquiryData - Supplies the inquiry data returned by the device of interest.
4856 PortCapabilities - Supplies the capabilities of the device object.
4865 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4866 PCDROM_DATA cdData
= (PCDROM_DATA
)(deviceExtension
+1);
4869 // Look for a Hitachi CDR-1750. Read-ahead must be disabled in order
4870 // to get this cdrom drive to work on scsi adapters that use PIO.
4873 if ((strncmp((PCHAR
)InquiryData
->VendorId
, "HITACHI CDR-1750S", strlen("HITACHI CDR-1750S")) == 0 ||
4874 strncmp((PCHAR
)InquiryData
->VendorId
, "HITACHI CDR-3650/1650S", strlen("HITACHI CDR-3650/1650S")) == 0)
4875 && PortCapabilities
->AdapterUsesPio
) {
4877 DebugPrint((1, "CdRom ScanForSpecial: Found Hitachi CDR-1750S.\n"));
4880 // Setup an error handler to reinitialize the cd rom after it is reset.
4883 deviceExtension
->ClassError
= HitachProcessError
;
4885 } else if (( RtlCompareMemory( InquiryData
->VendorId
,"FUJITSU", 7 ) == 7 ) &&
4886 (( RtlCompareMemory( InquiryData
->ProductId
,"FMCD-101", 8 ) == 8 ) ||
4887 ( RtlCompareMemory( InquiryData
->ProductId
,"FMCD-102", 8 ) == 8 ))) {
4890 // When Read command is issued to FMCD-101 or FMCD-102 and there is a music
4891 // cd in it. It takes longer time than SCSI_CDROM_TIMEOUT before returning
4895 deviceExtension
->TimeOutValue
= 20;
4897 } else if (( RtlCompareMemory( InquiryData
->VendorId
,"TOSHIBA", 7) == 7) &&
4898 (( RtlCompareMemory( InquiryData
->ProductId
,"CD-ROM XM-34", 12) == 12))) {
4900 SCSI_REQUEST_BLOCK srb
;
4907 // Set the density code and the error handler.
4910 length
= (sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH
);
4912 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
4915 // Build the MODE SENSE CDB.
4919 cdb
= (PCDB
)srb
.Cdb
;
4922 // Set timeout value from device extension.
4925 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
4927 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
4928 cdb
->MODE_SENSE
.PageCode
= 0x1;
4929 cdb
->MODE_SENSE
.AllocationLength
= (UCHAR
)length
;
4931 buffer
= ExAllocatePool(NonPagedPoolCacheAligned
, (sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH
));
4936 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
4942 ((PERROR_RECOVERY_DATA
)buffer
)->BlockDescriptor
.DensityCode
= 0x83;
4943 ((PERROR_RECOVERY_DATA
)buffer
)->Header
.ModeDataLength
= 0x0;
4945 RtlCopyMemory(&cdData
->u1
.Header
, buffer
, sizeof(ERROR_RECOVERY_DATA
));
4947 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
4950 // Build the MODE SENSE CDB.
4954 cdb
= (PCDB
)srb
.Cdb
;
4957 // Set timeout value from device extension.
4960 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
4962 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
4963 cdb
->MODE_SELECT
.PFBit
= 1;
4964 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)length
;
4966 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
4972 if (!NT_SUCCESS(status
)) {
4974 "Cdrom.ScanForSpecial: Setting density code on Toshiba failed [%x]\n",
4978 deviceExtension
->ClassError
= ToshibaProcessError
;
4985 // Determine special CD-DA requirements.
4988 if (RtlCompareMemory( InquiryData
->VendorId
,"PLEXTOR",7) == 7) {
4989 cdData
->XAFlags
|= PLEXTOR_CDDA
;
4990 } else if (RtlCompareMemory ( InquiryData
->VendorId
,"NEC",3) == 3) {
4991 cdData
->XAFlags
|= NEC_CDDA
;
5000 PDEVICE_OBJECT DeviceObject
,
5001 PSCSI_REQUEST_BLOCK Srb
,
5007 Routine Description:
5009 This routine checks the type of error. If the error indicates CD-ROM the
5010 CD-ROM needs to be reinitialized then a Mode sense command is sent to the
5011 device. This command disables read-ahead for the device.
5015 DeviceObject - Supplies a pointer to the device object.
5017 Srb - Supplies a pointer to the failing Srb.
5030 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
5031 PSENSE_DATA senseBuffer
= Srb
->SenseInfoBuffer
;
5032 LARGE_INTEGER largeInt
;
5034 PIO_STACK_LOCATION irpStack
;
5036 PSCSI_REQUEST_BLOCK srb
;
5037 PCOMPLETION_CONTEXT context
;
5041 UNREFERENCED_PARAMETER(Status
);
5042 UNREFERENCED_PARAMETER(Retry
);
5044 largeInt
.QuadPart
= (LONGLONG
) 1;
5047 // Check the status. The initialization command only needs to be sent
5048 // if UNIT ATTENTION is returned.
5051 if (!(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
)) {
5054 // The drive does not require reinitialization.
5061 // Found a bad HITACHI cd-rom. These devices do not work with PIO
5062 // adapters when read-ahead is enabled. Read-ahead is disabled by
5063 // a mode select command. The mode select page code is zero and the
5064 // length is 6 bytes. All of the other bytes should be zero.
5068 if ((senseBuffer
->SenseKey
& 0xf) == SCSI_SENSE_UNIT_ATTENTION
) {
5070 DebugPrint((1, "HitachiProcessError: Reinitializing the CD-ROM.\n"));
5073 // Send the special mode select command to disable read-ahead
5074 // on the CD-ROM reader.
5077 alignment
= DeviceObject
->AlignmentRequirement
?
5078 DeviceObject
->AlignmentRequirement
: 1;
5080 context
= ExAllocatePool(
5082 sizeof(COMPLETION_CONTEXT
) + HITACHI_MODE_DATA_SIZE
+ alignment
5085 if (context
== NULL
) {
5088 // If there is not enough memory to fulfill this request,
5089 // simply return. A subsequent retry will fail and another
5090 // chance to start the unit.
5096 context
->DeviceObject
= DeviceObject
;
5097 srb
= &context
->Srb
;
5099 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
5102 // Write length to SRB.
5105 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
5108 // Set up SCSI bus address.
5111 srb
->PathId
= deviceExtension
->PathId
;
5112 srb
->TargetId
= deviceExtension
->TargetId
;
5113 srb
->Lun
= deviceExtension
->Lun
;
5115 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
5116 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
5119 // Set the transfer length.
5122 srb
->DataTransferLength
= HITACHI_MODE_DATA_SIZE
;
5123 srb
->SrbFlags
= SRB_FLAGS_DATA_OUT
| SRB_FLAGS_DISABLE_AUTOSENSE
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
5126 // The data buffer must be aligned.
5129 srb
->DataBuffer
= (PVOID
) (((ULONG_PTR
) (context
+ 1) + (alignment
- 1)) &
5134 // Build the HITACHI read-ahead mode select CDB.
5138 cdb
= (PCDB
)srb
->Cdb
;
5139 cdb
->MODE_SENSE
.LogicalUnitNumber
= srb
->Lun
;
5140 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SELECT
;
5141 cdb
->MODE_SENSE
.AllocationLength
= HITACHI_MODE_DATA_SIZE
;
5144 // Initialize the mode sense data.
5147 modePage
= srb
->DataBuffer
;
5149 RtlZeroMemory(modePage
, HITACHI_MODE_DATA_SIZE
);
5152 // Set the page length field to 6.
5158 // Build the asynchronous request to be sent to the port driver.
5161 irp
= IoBuildAsynchronousFsdRequest(IRP_MJ_WRITE
,
5164 srb
->DataTransferLength
,
5168 IoSetCompletionRoutine(irp
,
5169 (PIO_COMPLETION_ROUTINE
)ScsiClassAsynchronousCompletion
,
5175 irpStack
= IoGetNextIrpStackLocation(irp
);
5177 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
5179 srb
->OriginalRequest
= irp
;
5182 // Save SRB address in next stack for port driver.
5185 irpStack
->Parameters
.Scsi
.Srb
= (PVOID
)srb
;
5188 // Set up IRP Address.
5191 (VOID
)IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
5198 ToshibaProcessErrorCompletion(
5199 PDEVICE_OBJECT DeviceObject
,
5206 Routine Description:
5208 Completion routine for the ClassError routine to handle older Toshiba units
5209 that require setting the density code.
5213 DeviceObject - Supplies a pointer to the device object.
5215 Irp - Pointer to irp created to set the density code.
5217 Context - Supplies a pointer to the Mode Select Srb.
5222 STATUS_MORE_PROCESSING_REQUIRED
5228 PSCSI_REQUEST_BLOCK srb
= Context
;
5231 // Check for a frozen queue.
5234 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
5237 // Unfreeze the queue getting the device object from the context.
5240 ScsiClassReleaseQueue(DeviceObject
);
5244 // Free all of the allocations.
5247 ExFreePool(srb
->DataBuffer
);
5249 IoFreeMdl(Irp
->MdlAddress
);
5253 // Indicate the I/O system should stop processing the Irp completion.
5256 return STATUS_MORE_PROCESSING_REQUIRED
;
5261 ToshibaProcessError(
5262 PDEVICE_OBJECT DeviceObject
,
5263 PSCSI_REQUEST_BLOCK Srb
,
5270 Routine Description:
5272 This routine checks the type of error. If the error indicates a unit attention,
5273 the density code needs to be set via a Mode select command.
5277 DeviceObject - Supplies a pointer to the device object.
5279 Srb - Supplies a pointer to the failing Srb.
5292 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
5293 PCDROM_DATA cdData
= (PCDROM_DATA
)(deviceExtension
+1);
5294 PSENSE_DATA senseBuffer
= Srb
->SenseInfoBuffer
;
5295 PIO_STACK_LOCATION irpStack
;
5297 PSCSI_REQUEST_BLOCK srb
;
5303 if (!(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
)) {
5308 // The Toshiba's require the density code to be set on power up and media changes.
5311 if ((senseBuffer
->SenseKey
& 0xf) == SCSI_SENSE_UNIT_ATTENTION
) {
5314 irp
= IoAllocateIrp((CCHAR
)(deviceExtension
->DeviceObject
->StackSize
+1),
5321 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
5328 length
= sizeof(ERROR_RECOVERY_DATA
);
5329 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, length
);
5336 irp
->MdlAddress
= IoAllocateMdl(dataBuffer
,
5342 if (!irp
->MdlAddress
) {
5344 ExFreePool(dataBuffer
);
5353 MmBuildMdlForNonPagedPool(irp
->MdlAddress
);
5355 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
5357 srb
->DataBuffer
= dataBuffer
;
5358 cdb
= (PCDB
)srb
->Cdb
;
5364 IoSetNextIrpStackLocation(irp
);
5365 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
5366 irp
->IoStatus
.Information
= 0;
5368 irp
->UserBuffer
= NULL
;
5371 // Save the device object and irp in a private stack location.
5374 irpStack
= IoGetCurrentIrpStackLocation(irp
);
5375 irpStack
->DeviceObject
= deviceExtension
->DeviceObject
;
5378 // Construct the IRP stack for the lower level driver.
5381 irpStack
= IoGetNextIrpStackLocation(irp
);
5382 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
5383 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_OUT
;
5384 irpStack
->Parameters
.Scsi
.Srb
= srb
;
5386 IoSetCompletionRoutine(irp
,
5387 ToshibaProcessErrorCompletion
,
5393 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
5394 srb
->PathId
= deviceExtension
->PathId
;
5395 srb
->TargetId
= deviceExtension
->TargetId
;
5396 srb
->Lun
= deviceExtension
->Lun
;
5397 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
5398 srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
5399 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
5401 srb
->OriginalRequest
= irp
;
5402 srb
->SenseInfoBufferLength
= 0;
5405 // Set the transfer length.
5408 srb
->DataTransferLength
= length
;
5409 srb
->SrbFlags
= SRB_FLAGS_DATA_OUT
| SRB_FLAGS_DISABLE_AUTOSENSE
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
5413 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
5414 cdb
->MODE_SELECT
.PFBit
= 1;
5415 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)length
;
5418 // Copy the Mode page into the databuffer.
5421 RtlCopyMemory(srb
->DataBuffer
, &cdData
->u1
.Header
, length
);
5424 // Set the density code.
5427 ((PERROR_RECOVERY_DATA
)srb
->DataBuffer
)->BlockDescriptor
.DensityCode
= 0x83;
5429 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
5436 IN PDEVICE_OBJECT DeviceObject
5441 Routine Description:
5443 This routine determines if the cd is currently playing music.
5447 DeviceObject - Device object to test.
5451 TRUE if the device is playing music.
5455 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
5457 IO_STATUS_BLOCK ioStatus
;
5460 PSUB_Q_CURRENT_POSITION currentBuffer
;
5462 if (!PLAY_ACTIVE(deviceExtension
)) {
5466 currentBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, sizeof(SUB_Q_CURRENT_POSITION
));
5468 if (currentBuffer
== NULL
) {
5472 ((PCDROM_SUB_Q_DATA_FORMAT
) currentBuffer
)->Format
= IOCTL_CDROM_CURRENT_POSITION
;
5473 ((PCDROM_SUB_Q_DATA_FORMAT
) currentBuffer
)->Track
= 0;
5476 // Create notification event object to be used to signal the
5477 // request completion.
5480 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
5483 // Build the synchronous request to be sent to the port driver
5484 // to perform the request.
5487 irp
= IoBuildDeviceIoControlRequest(IOCTL_CDROM_READ_Q_CHANNEL
,
5488 deviceExtension
->DeviceObject
,
5490 sizeof(CDROM_SUB_Q_DATA_FORMAT
),
5492 sizeof(SUB_Q_CURRENT_POSITION
),
5498 ExFreePool(currentBuffer
);
5503 // Pass request to port driver and wait for request to complete.
5506 status
= IoCallDriver(deviceExtension
->DeviceObject
, irp
);
5508 if (status
== STATUS_PENDING
) {
5509 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
5510 status
= ioStatus
.Status
;
5513 if (!NT_SUCCESS(status
)) {
5514 ExFreePool(currentBuffer
);
5518 ExFreePool(currentBuffer
);
5520 return(PLAY_ACTIVE(deviceExtension
));
5524 IO_COMPLETION_ROUTINE CdRomMediaChangeCompletion
;
5527 CdRomMediaChangeCompletion(
5528 PDEVICE_OBJECT DeviceObject
,
5535 Routine Description:
5537 This routine handles the completion of the test unit ready irps
5538 used to determine if the media has changed. If the media has
5539 changed, this code signals the named event to wake up other
5540 system services that react to media change (aka AutoPlay).
5544 DeviceObject - the object for the completion
5545 Irp - the IRP being completed
5546 Context - the SRB from the IRP
5555 PSCSI_REQUEST_BLOCK srb
= (PSCSI_REQUEST_BLOCK
) Context
;
5556 PIO_STACK_LOCATION cdStack
= IoGetCurrentIrpStackLocation(Irp
);
5557 PIO_STACK_LOCATION irpNextStack
= IoGetNextIrpStackLocation(Irp
);
5558 PDEVICE_EXTENSION deviceExtension
;
5559 PDEVICE_EXTENSION physicalExtension
;
5560 PSENSE_DATA senseBuffer
;
5565 DeviceObject
= cdStack
->DeviceObject
;
5566 ASSERT(DeviceObject
);
5568 deviceExtension
= DeviceObject
->DeviceExtension
;
5569 physicalExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
5570 cddata
= (PCDROM_DATA
)(deviceExtension
+ 1);
5572 ASSERT(cddata
->MediaChangeIrp
== NULL
);
5575 // If the sense data field is valid, look for a media change.
5576 // otherwise this iteration of the polling will just assume nothing
5580 DebugPrint((3, "CdRomMediaChangeHandler: Completing Autorun Irp 0x%lx "
5582 Irp
, deviceExtension
->DeviceNumber
));
5584 if (srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) {
5585 if (srb
->SenseInfoBufferLength
>= FIELD_OFFSET(SENSE_DATA
, CommandSpecificInformation
)) {
5588 // See if this is a media change.
5591 senseBuffer
= srb
->SenseInfoBuffer
;
5592 if ((senseBuffer
->SenseKey
& 0x0f) == SCSI_SENSE_UNIT_ATTENTION
) {
5593 if (senseBuffer
->AdditionalSenseCode
== SCSI_ADSENSE_MEDIUM_CHANGED
) {
5595 DebugPrint((1, "CdRomMediaChangeCompletion: New media inserted "
5596 "into CdRom%d [irp = 0x%lx]\n",
5597 deviceExtension
->DeviceNumber
, Irp
));
5600 // Media change event occurred - signal the named event.
5603 KeSetEvent(deviceExtension
->MediaChangeEvent
,
5607 deviceExtension
->MediaChangeNoMedia
= FALSE
;
5611 if (DeviceObject
->Vpb
->Flags
& VPB_MOUNTED
) {
5614 // Must remember the media changed and force the
5615 // file system to verify on next access
5618 DeviceObject
->Flags
|= DO_VERIFY_VOLUME
;
5621 physicalExtension
->MediaChangeCount
++;
5623 } else if(((senseBuffer
->SenseKey
& 0x0f) == SCSI_SENSE_NOT_READY
)&&
5624 (senseBuffer
->AdditionalSenseCode
== SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
)&&
5625 (!deviceExtension
->MediaChangeNoMedia
)){
5628 // If there was no media in the device then signal the waiters if
5629 // we haven't already done so before.
5632 DebugPrint((1, "CdRomMediaChangeCompletion: No media in device"
5633 "CdRom%d [irp = 0x%lx]\n",
5634 deviceExtension
->DeviceNumber
, Irp
));
5636 KeSetEvent(deviceExtension
->MediaChangeEvent
,
5640 deviceExtension
->MediaChangeNoMedia
= TRUE
;
5644 } else if((srb
->SrbStatus
== SRB_STATUS_SUCCESS
)&&
5645 (deviceExtension
->MediaChangeNoMedia
)) {
5647 // We didn't have any media before and now the requests are succeeding
5648 // we probably missed the Media change somehow. Signal the change
5652 DebugPrint((1, "CdRomMediaChangeCompletion: Request completed normally"
5653 "for CdRom%d which was marked w/NoMedia [irp = 0x%lx]\n",
5654 deviceExtension
->DeviceNumber
, Irp
));
5656 KeSetEvent(deviceExtension
->MediaChangeEvent
,
5660 deviceExtension
->MediaChangeNoMedia
= FALSE
;
5664 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
5665 ScsiClassReleaseQueue(deviceExtension
->DeviceObject
);
5669 // Remember the IRP and SRB for use the next time.
5672 irpNextStack
->Parameters
.Scsi
.Srb
= srb
;
5673 cddata
->MediaChangeIrp
= Irp
;
5675 if (deviceExtension
->ClassError
) {
5681 // Throw away the status and retry values. Just give the error routine a chance
5682 // to do what it needs to.
5685 deviceExtension
->ClassError(DeviceObject
,
5691 IoStartNextPacket(DeviceObject
, FALSE
);
5693 return STATUS_MORE_PROCESSING_REQUIRED
;
5699 IN PDEVICE_OBJECT DeviceObject
,
5705 Routine Description:
5707 This routine handles the once per second timer provided by the
5708 Io subsystem. It is only used when the cdrom device itself is
5709 a candidate for autoplay support. It should never be called if
5710 the cdrom device is a changer device.
5714 DeviceObject - what to check.
5727 PLIST_ENTRY listEntry
;
5729 PIO_STACK_LOCATION irpStack
;
5730 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
5732 cddata
= (PCDROM_DATA
)(deviceExtension
+ 1);
5734 if (cddata
->MediaChange
) {
5735 if (cddata
->MediaChangeIrp
!= NULL
) {
5738 // Media change support is active and the IRP is waiting.
5739 // Decrement the timer.
5740 // There is no MP protection on the timer counter. This
5741 // code is the only code that will manipulate the timer
5742 // and only one instance of it should be running at any
5746 cddata
->MediaChangeCountDown
--;
5749 cddata
->MediaChangeIrpTimeInUse
= 0;
5750 cddata
->MediaChangeIrpLost
= FALSE
;
5753 if (!cddata
->MediaChangeCountDown
) {
5754 PSCSI_REQUEST_BLOCK srb
;
5755 PIO_STACK_LOCATION irpNextStack
;
5762 cddata
->MediaChangeCountDown
= MEDIA_CHANGE_DEFAULT_TIME
;
5765 // Prepare the IRP for the test unit ready
5768 irp
= cddata
->MediaChangeIrp
;
5769 cddata
->MediaChangeIrp
= NULL
;
5771 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
5772 irp
->IoStatus
.Information
= 0;
5774 irp
->UserBuffer
= NULL
;
5777 // If the irp is sent down when the volume needs to be
5778 // verified, CdRomUpdateGeometryCompletion won't complete
5779 // it since it's not associated with a thread. Marking
5780 // it to override the verify causes it always be sent
5781 // to the port driver
5784 irpStack
= IoGetCurrentIrpStackLocation(irp
);
5785 irpStack
->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
5787 irpNextStack
= IoGetNextIrpStackLocation(irp
);
5788 irpNextStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
5789 irpNextStack
->Parameters
.DeviceIoControl
.IoControlCode
=
5790 IOCTL_SCSI_EXECUTE_NONE
;
5793 // Prepare the SRB for execution.
5796 srb
= irpNextStack
->Parameters
.Scsi
.Srb
;
5797 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
5799 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
5800 srb
->PathId
= deviceExtension
->PathId
;
5801 srb
->TargetId
= deviceExtension
->TargetId
;
5802 srb
->Lun
= deviceExtension
->Lun
;
5803 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
5804 srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
|
5805 SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
5806 srb
->DataTransferLength
= 0;
5807 srb
->OriginalRequest
= irp
;
5809 RtlZeroMemory(srb
->SenseInfoBuffer
, SENSE_BUFFER_SIZE
);
5810 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
5812 cdb
= (PCDB
) &srb
->Cdb
[0];
5813 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_TEST_UNIT_READY
;
5814 cdb
->CDB6GENERIC
.LogicalUnitNumber
= srb
->Lun
;
5817 // Setup the IRP to perform a test unit ready.
5820 IoSetCompletionRoutine(irp
,
5821 CdRomMediaChangeCompletion
,
5828 // Issue the request.
5831 IoStartPacket(DeviceObject
, irp
, NULL
, NULL
);
5836 if(cddata
->MediaChangeIrpLost
== FALSE
) {
5837 if(cddata
->MediaChangeIrpTimeInUse
++ >
5838 MEDIA_CHANGE_TIMEOUT_TIME
) {
5840 DebugPrint((0, "CdRom%d: AutoPlay has lost it's irp and "
5841 "doesn't know where to find it. Leave it "
5842 "alone and it'll come home dragging it's "
5843 "stack behind it.\n",
5844 deviceExtension
->DeviceNumber
));
5845 cddata
->MediaChangeIrpLost
= TRUE
;
5854 // Process all generic timer IRPS in the timer list. As IRPs are pulled
5855 // off of the TimerIrpList they must be remembered in the first loop
5856 // if they are not sent to the lower driver. After all items have
5857 // been pulled off the list, it is possible to put the held IRPs back
5858 // into the TimerIrpList.
5862 if (IsListEmpty(&cddata
->TimerIrpList
)) {
5865 listEntry
= ExInterlockedRemoveHeadList(&cddata
->TimerIrpList
,
5866 &cddata
->TimerIrpSpinLock
);
5871 // There is something in the timer list. Pick up the IRP and
5872 // see if it is ready to be submitted.
5875 irp
= CONTAINING_RECORD(listEntry
, IRP
, Tail
.Overlay
.ListEntry
);
5876 irpStack
= IoGetCurrentIrpStackLocation(irp
);
5878 if (irpStack
->Parameters
.Others
.Argument3
) {
5882 // Decrement the countdown timer and put the IRP back in the list.
5885 count
= (ULONG_PTR
)irpStack
->Parameters
.Others
.Argument3
;
5887 irpStack
->Parameters
.Others
.Argument3
= (PVOID
) count
;
5889 ASSERT(irp
->AssociatedIrp
.MasterIrp
== NULL
);
5891 irp
->AssociatedIrp
.MasterIrp
= (PVOID
) heldIrpList
;
5898 // Submit this IRP to the lower driver. This IRP does not
5899 // need to be remembered here. It will be handled again when
5903 DebugPrint((1, "CdRomTickHandler: Reissuing request %lx (thread = %lx)\n", irp
, irp
->Tail
.Overlay
.Thread
));
5906 // feed this to the appropriate port driver
5909 IoCallDriver (deviceExtension
->PortDeviceObject
, irp
);
5914 // Pick up the next IRP from the timer list.
5917 listEntry
= ExInterlockedRemoveHeadList(&cddata
->TimerIrpList
,
5918 &cddata
->TimerIrpSpinLock
);
5922 // Move all held IRPs back onto the timer list.
5925 while (heldIrpList
) {
5928 // Save the single list pointer before queueing this IRP.
5931 nextIrp
= (PIRP
) heldIrpList
->AssociatedIrp
.MasterIrp
;
5932 heldIrpList
->AssociatedIrp
.MasterIrp
= NULL
;
5935 // Return the held IRP to the timer list.
5938 ExInterlockedInsertTailList(&cddata
->TimerIrpList
,
5939 &heldIrpList
->Tail
.Overlay
.ListEntry
,
5940 &cddata
->TimerIrpSpinLock
);
5943 // Continue processing the held IRPs
5946 heldIrpList
= nextIrp
;
5952 CdRomCheckRegistryForMediaChangeValue(
5953 IN PUNICODE_STRING RegistryPath
,
5954 IN ULONG DeviceNumber
5959 Routine Description:
5961 The user must specify that AutoPlay is to run on the platform
5962 by setting the registry value HKEY_LOCAL_MACHINE\System\CurrentControlSet\
5963 Services\Cdrom\Autorun:REG_DWORD:1.
5965 The user can override the global setting to enable or disable Autorun on a
5966 specific cdrom device by setting the key HKEY_LOCAL_MACHINE\System\
5967 CurrentControlSet\Services\Cdrom\Device<N>\Autorun:REG_DWORD to one or zero.
5968 (CURRENTLY UNIMPLEMENTED)
5970 If this registry value does not exist or contains the value zero then
5971 the timer to check for media change does not run.
5975 RegistryPath - pointer to the unicode string inside
5976 ...\CurrentControlSet\Services\Cdrom
5977 DeviceNumber - The number of the device object
5981 TRUE - Autorun is enabled.
5987 #define ITEMS_TO_QUERY 2 /* always 1 greater than what is searched */
5988 PRTL_QUERY_REGISTRY_TABLE parameters
= NULL
;
5996 ANSI_STRING paramNum
;
5998 UNICODE_STRING paramStr
;
6000 UNICODE_STRING paramSuffix
;
6001 UNICODE_STRING paramPath
;
6002 UNICODE_STRING paramDevPath
;
6005 // First append \Parameters to the passed in registry path
6008 RtlInitUnicodeString(¶mStr
, L
"\\Parameters");
6010 RtlInitUnicodeString(¶mPath
, NULL
);
6012 paramPath
.MaximumLength
= RegistryPath
->Length
+
6016 paramPath
.Buffer
= ExAllocatePool(PagedPool
, paramPath
.MaximumLength
);
6018 if(!paramPath
.Buffer
) {
6020 DebugPrint((1,"CdRomCheckRegAP: couldn't allocate paramPath\n"));
6025 RtlZeroMemory(paramPath
.Buffer
, paramPath
.MaximumLength
);
6026 RtlAppendUnicodeToString(¶mPath
, RegistryPath
->Buffer
);
6027 RtlAppendUnicodeToString(¶mPath
, paramStr
.Buffer
);
6029 DebugPrint((2, "CdRomCheckRegAP: paramPath [%d] = %ws\n",
6034 // build a counted ANSI string that contains
6035 // the suffix for the path
6038 sprintf(buf
, "\\Device%lu", DeviceNumber
);
6039 RtlInitAnsiString(¶mNum
, buf
);
6042 // Next convert this into a unicode string
6045 status
= RtlAnsiStringToUnicodeString(¶mSuffix
, ¶mNum
, TRUE
);
6047 if(!NT_SUCCESS(status
)) {
6048 DebugPrint((1,"CdRomCheckRegAP: couldn't convert paramNum to paramSuffix\n"));
6049 ExFreePool(paramPath
.Buffer
);
6053 RtlInitUnicodeString(¶mDevPath
, NULL
);
6056 // now build the device specific path
6059 paramDevPath
.MaximumLength
= paramPath
.Length
+
6060 paramSuffix
.Length
+
6062 paramDevPath
.Buffer
= ExAllocatePool(PagedPool
, paramDevPath
.MaximumLength
);
6064 if(!paramDevPath
.Buffer
) {
6065 RtlFreeUnicodeString(¶mSuffix
);
6066 ExFreePool(paramPath
.Buffer
);
6070 RtlZeroMemory(paramDevPath
.Buffer
, paramDevPath
.MaximumLength
);
6071 RtlAppendUnicodeToString(¶mDevPath
, paramPath
.Buffer
);
6072 RtlAppendUnicodeToString(¶mDevPath
, paramSuffix
.Buffer
);
6074 DebugPrint((2, "CdRomCheckRegAP: paramDevPath [%d] = %ws\n",
6078 parameters
= ExAllocatePool(NonPagedPool
,
6079 sizeof(RTL_QUERY_REGISTRY_TABLE
)*ITEMS_TO_QUERY
);
6084 // Check for the Autorun value.
6087 RtlZeroMemory(parameters
,
6088 (sizeof(RTL_QUERY_REGISTRY_TABLE
)*ITEMS_TO_QUERY
));
6090 parameters
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
6091 parameters
[0].Name
= L
"Autorun";
6092 parameters
[0].EntryContext
= &doRun
;
6093 parameters
[0].DefaultType
= REG_DWORD
;
6094 parameters
[0].DefaultData
= &zero
;
6095 parameters
[0].DefaultLength
= sizeof(ULONG
);
6097 status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
| RTL_REGISTRY_OPTIONAL
,
6098 RegistryPath
->Buffer
,
6103 DebugPrint((2, "CdRomCheckRegAP: cdrom/Autorun flag = %d\n", doRun
));
6105 RtlZeroMemory(parameters
,
6106 (sizeof(RTL_QUERY_REGISTRY_TABLE
)*ITEMS_TO_QUERY
));
6108 parameters
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
6109 parameters
[0].Name
= L
"Autorun";
6110 parameters
[0].EntryContext
= &tmp
;
6111 parameters
[0].DefaultType
= REG_DWORD
;
6112 parameters
[0].DefaultData
= &doRun
;
6113 parameters
[0].DefaultLength
= sizeof(ULONG
);
6115 status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
| RTL_REGISTRY_OPTIONAL
,
6121 DebugPrint((2, "CdRomCheckRegAP: cdrom/parameters/autorun flag = %d\n", tmp
));
6123 RtlZeroMemory(parameters
,
6124 (sizeof(RTL_QUERY_REGISTRY_TABLE
) * ITEMS_TO_QUERY
));
6126 parameters
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
6127 parameters
[0].Name
= L
"Autorun";
6128 parameters
[0].EntryContext
= &doRun
;
6129 parameters
[0].DefaultType
= REG_DWORD
;
6130 parameters
[0].DefaultData
= &tmp
;
6131 parameters
[0].DefaultLength
= sizeof(ULONG
);
6133 status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
| RTL_REGISTRY_OPTIONAL
,
6134 paramDevPath
.Buffer
,
6139 DebugPrint((1, "CdRomCheckRegAP: cdrom/parameters/device%d/autorun flag = %d\n", DeviceNumber
, doRun
));
6141 ExFreePool(parameters
);
6145 ExFreePool(paramPath
.Buffer
);
6146 ExFreePool(paramDevPath
.Buffer
);
6147 RtlFreeUnicodeString(¶mSuffix
);
6149 DebugPrint((1, "CdRomCheckRegAP: Autoplay for device %d is %s\n",
6151 (doRun
? "on" : "off")));
6164 IN PDEVICE_OBJECT DeviceObject
,
6171 Routine Description:
6173 This routine is called by DriverEntry to determine whether a Sanyo 3-CD
6174 changer device is present.
6178 DeviceObject - Supplies the device object for the 'real' device.
6184 TRUE - if an Atapi changer device is found.
6191 PCHAR inquiryBuffer
;
6192 IO_STATUS_BLOCK ioStatus
;
6194 PSCSI_ADAPTER_BUS_INFO adapterInfo
;
6196 PINQUIRYDATA inquiryData
;
6197 PSCSI_INQUIRY_DATA lunInfo
;
6199 inquiryBuffer
= ExAllocatePool(NonPagedPool
, 2048);
6200 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
6201 irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA
,
6214 status
= IoCallDriver(DeviceObject
, irp
);
6216 if (status
== STATUS_PENDING
) {
6217 KeWaitForSingleObject(&event
, Executive
, KernelMode
, FALSE
, NULL
);
6218 status
= ioStatus
.Status
;
6221 if (!NT_SUCCESS(status
)) {
6225 adapterInfo
= (PVOID
) inquiryBuffer
;
6227 for (scsiBus
=0; scsiBus
< (ULONG
)adapterInfo
->NumberOfBuses
; scsiBus
++) {
6230 // Get the SCSI bus scan data for this bus.
6233 lunInfo
= (PVOID
) (inquiryBuffer
+ adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
);
6237 if (lunInfo
->PathId
== PathId
&& lunInfo
->TargetId
== TargetId
) {
6239 inquiryData
= (PVOID
) lunInfo
->InquiryData
;
6241 if (RtlCompareMemory(inquiryData
->VendorId
, "TORiSAN CD-ROM CDR-C", 20) == 20) {
6242 ExFreePool(inquiryBuffer
);
6246 ExFreePool(inquiryBuffer
);
6250 if (!lunInfo
->NextInquiryDataOffset
) {
6254 lunInfo
= (PVOID
) (inquiryBuffer
+ lunInfo
->NextInquiryDataOffset
);
6258 ExFreePool(inquiryBuffer
);
6264 IsThisAnAtapiChanger(
6265 IN PDEVICE_OBJECT DeviceObject
,
6266 OUT PULONG DiscsPresent
6271 Routine Description:
6273 This routine is called by DriverEntry to determine whether an Atapi
6274 changer device is present.
6278 DeviceObject - Supplies the device object for the 'real' device.
6280 DiscsPresent - Supplies a pointer to the number of Discs supported by the changer.
6284 TRUE - if an Atapi changer device is found.
6289 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
6290 PMECHANICAL_STATUS_INFORMATION_HEADER mechanicalStatusBuffer
;
6292 SCSI_REQUEST_BLOCK srb
;
6293 PCDB cdb
= (PCDB
) &srb
.Cdb
[0];
6294 BOOLEAN retVal
= FALSE
;
6299 // Some devices can't handle 12 byte CDB's gracefully
6302 if(deviceExtension
->DeviceFlags
& DEV_NO_12BYTE_CDB
) {
6309 // Build and issue the mechanical status command.
6312 mechanicalStatusBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
6313 sizeof(MECHANICAL_STATUS_INFORMATION_HEADER
));
6315 if (!mechanicalStatusBuffer
) {
6320 // Build and send the Mechanism status CDB.
6323 RtlZeroMemory(&srb
, sizeof(srb
));
6326 srb
.TimeOutValue
= 20;
6328 cdb
->MECH_STATUS
.OperationCode
= SCSIOP_MECHANISM_STATUS
;
6329 cdb
->MECH_STATUS
.AllocationLength
[1] = sizeof(MECHANICAL_STATUS_INFORMATION_HEADER
);
6331 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
6333 mechanicalStatusBuffer
,
6334 sizeof(MECHANICAL_STATUS_INFORMATION_HEADER
),
6338 if (status
== STATUS_SUCCESS
) {
6341 // Indicate number of slots available
6344 *DiscsPresent
= mechanicalStatusBuffer
->NumberAvailableSlots
;
6345 if (*DiscsPresent
> 1) {
6350 // If only one disc, no need for this driver.
6358 // Device doesn't support this command.
6364 ExFreePool(mechanicalStatusBuffer
);
6372 IsThisAMultiLunDevice(
6373 IN PDEVICE_OBJECT DeviceObject
,
6374 IN PDEVICE_OBJECT PortDeviceObject
6378 Routine Description:
6380 This routine is called to determine whether a multi-lun
6385 DeviceObject - Supplies the device object for the 'real' device.
6389 TRUE - if a Multi-lun device is found.
6394 PSCSI_INQUIRY_DATA lunInfo
;
6395 PSCSI_ADAPTER_BUS_INFO adapterInfo
;
6396 PDEVICE_EXTENSION deviceExtension
= (PDEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
6397 PINQUIRYDATA inquiryData
;
6402 status
= ScsiClassGetInquiryData(PortDeviceObject
, (PSCSI_ADAPTER_BUS_INFO
*) &buffer
);
6404 if (!NT_SUCCESS(status
)) {
6405 DebugPrint((1,"IsThisAMultiLunDevice: ScsiClassGetInquiryData failed\n"));
6409 adapterInfo
= (PVOID
) buffer
;
6412 // For each SCSI bus this adapter supports ...
6415 for (scsiBus
=0; scsiBus
< adapterInfo
->NumberOfBuses
; scsiBus
++) {
6418 // Get the SCSI bus scan data for this bus.
6421 lunInfo
= (PVOID
) (buffer
+ adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
);
6423 while (adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
) {
6425 inquiryData
= (PVOID
)lunInfo
->InquiryData
;
6427 if ((lunInfo
->PathId
== deviceExtension
->PathId
) &&
6428 (lunInfo
->TargetId
== deviceExtension
->TargetId
) &&
6429 (inquiryData
->DeviceType
== READ_ONLY_DIRECT_ACCESS_DEVICE
)) {
6431 DebugPrint((1,"IsThisAMultiLunDevice: Vendor string is %.24s\n",
6432 inquiryData
->VendorId
));
6435 // If this device has more than one cdrom-type lun then we
6436 // won't support autoplay on it
6446 // Get next LunInfo.
6449 if (lunInfo
->NextInquiryDataOffset
== 0) {
6453 lunInfo
= (PVOID
) (buffer
+ lunInfo
->NextInquiryDataOffset
);
6462 IO_COMPLETION_ROUTINE CdRomUpdateGeometryCompletion
;
6465 CdRomUpdateGeometryCompletion(
6466 PDEVICE_OBJECT DeviceObject
,
6473 Routine Description:
6475 This routine andles the completion of the test unit ready irps
6476 used to determine if the media has changed. If the media has
6477 changed, this code signals the named event to wake up other
6478 system services that react to media change (aka AutoPlay).
6482 DeviceObject - the object for the completion
6483 Irp - the IRP being completed
6484 Context - the SRB from the IRP
6493 PSCSI_REQUEST_BLOCK srb
= (PSCSI_REQUEST_BLOCK
) Context
;
6494 PREAD_CAPACITY_DATA readCapacityBuffer
;
6495 PDEVICE_EXTENSION deviceExtension
;
6496 PIO_STACK_LOCATION irpStack
;
6499 ULONG_PTR retryCount
;
6505 // Get items saved in the private IRP stack location.
6508 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
6509 retryCount
= (ULONG_PTR
) irpStack
->Parameters
.Others
.Argument1
;
6510 originalIrp
= (PIRP
) irpStack
->Parameters
.Others
.Argument2
;
6512 if (!DeviceObject
) {
6513 DeviceObject
= irpStack
->DeviceObject
;
6515 ASSERT(DeviceObject
);
6517 deviceExtension
= DeviceObject
->DeviceExtension
;
6518 cddata
= (PCDROM_DATA
) (deviceExtension
+ 1);
6519 readCapacityBuffer
= srb
->DataBuffer
;
6521 if ((NT_SUCCESS(Irp
->IoStatus
.Status
)) && (SRB_STATUS(srb
->SrbStatus
) == SRB_STATUS_SUCCESS
)) {
6525 DebugPrint((2, "CdRomUpdateCapacityCompletion: [%lx] successful completion of buddy-irp %lx\n", originalIrp
, Irp
));
6527 // Copy sector size from read capacity buffer to device extension
6528 // in reverse byte order.
6531 from
= (PFOUR_BYTE
) &readCapacityBuffer
->BytesPerBlock
;
6532 to
= (PFOUR_BYTE
) &deviceExtension
->DiskGeometry
->BytesPerSector
;
6533 to
->Byte0
= from
->Byte3
;
6534 to
->Byte1
= from
->Byte2
;
6535 to
->Byte2
= from
->Byte1
;
6536 to
->Byte3
= from
->Byte0
;
6539 // Using the new BytesPerBlock, calculate and store the SectorShift.
6542 WHICH_BIT(deviceExtension
->DiskGeometry
->BytesPerSector
, deviceExtension
->SectorShift
);
6545 // Copy last sector in reverse byte order.
6548 from
= (PFOUR_BYTE
) &readCapacityBuffer
->LogicalBlockAddress
;
6549 to
= (PFOUR_BYTE
) &lastSector
;
6550 to
->Byte0
= from
->Byte3
;
6551 to
->Byte1
= from
->Byte2
;
6552 to
->Byte2
= from
->Byte1
;
6553 to
->Byte3
= from
->Byte0
;
6554 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(lastSector
+ 1);
6557 // Calculate number of cylinders.
6560 deviceExtension
->DiskGeometry
->Cylinders
.QuadPart
= (LONGLONG
)((lastSector
+ 1)/(32 * 64));
6561 deviceExtension
->PartitionLength
.QuadPart
=
6562 (deviceExtension
->PartitionLength
.QuadPart
<< deviceExtension
->SectorShift
);
6563 deviceExtension
->DiskGeometry
->MediaType
= RemovableMedia
;
6566 // Assume sectors per track are 32;
6569 deviceExtension
->DiskGeometry
->SectorsPerTrack
= 32;
6572 // Assume tracks per cylinder (number of heads) is 64.
6575 deviceExtension
->DiskGeometry
->TracksPerCylinder
= 64;
6579 DebugPrint((1, "CdRomUpdateCapacityCompletion: [%lx] unsuccessful completion of buddy-irp %lx (status - %lx)\n", originalIrp
, Irp
, Irp
->IoStatus
.Status
));
6581 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
6582 ScsiClassReleaseQueue(DeviceObject
);
6585 retry
= ScsiClassInterpretSenseInfo(DeviceObject
,
6596 DebugPrint((1, "CdRomUpdateCapacityCompletion: [%lx] Retrying request %lx .. thread is %lx\n", originalIrp
, Irp
, Irp
->Tail
.Overlay
.Thread
));
6598 // set up a one shot timer to get this process started over
6601 irpStack
->Parameters
.Others
.Argument1
= (PVOID
) retryCount
;
6602 irpStack
->Parameters
.Others
.Argument2
= (PVOID
) originalIrp
;
6603 irpStack
->Parameters
.Others
.Argument3
= (PVOID
) 2;
6606 // Setup the IRP to be submitted again in the timer routine.
6609 irpStack
= IoGetNextIrpStackLocation(Irp
);
6610 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
6611 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
6612 irpStack
->Parameters
.Scsi
.Srb
= srb
;
6613 IoSetCompletionRoutine(Irp
,
6614 CdRomUpdateGeometryCompletion
,
6621 // Set up the SRB for read capacity.
6624 srb
->CdbLength
= 10;
6625 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
6626 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
6628 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
6629 srb
->PathId
= deviceExtension
->PathId
;
6630 srb
->TargetId
= deviceExtension
->TargetId
;
6631 srb
->Lun
= deviceExtension
->Lun
;
6632 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
6633 srb
->SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
6634 srb
->DataTransferLength
= sizeof(READ_CAPACITY_DATA
);
6640 cdb
= (PCDB
) &srb
->Cdb
[0];
6641 cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
6642 cdb
->CDB10
.LogicalUnitNumber
= deviceExtension
->Lun
;
6645 // Requests queued onto this list will be sent to the
6646 // lower level driver during CdRomTickHandler
6649 ExInterlockedInsertHeadList(&cddata
->TimerIrpList
,
6650 &Irp
->Tail
.Overlay
.ListEntry
,
6651 &cddata
->TimerIrpSpinLock
);
6653 return STATUS_MORE_PROCESSING_REQUIRED
;
6657 // This has been bounced for a number of times. Error the
6658 // original request.
6661 originalIrp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
6662 RtlZeroMemory(deviceExtension
->DiskGeometry
, sizeof(DISK_GEOMETRY
));
6663 deviceExtension
->DiskGeometry
->BytesPerSector
= 2048;
6664 deviceExtension
->SectorShift
= 11;
6665 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(0x7fffffff);
6666 deviceExtension
->DiskGeometry
->MediaType
= RemovableMedia
;
6671 // Set up reasonable defaults
6674 RtlZeroMemory(deviceExtension
->DiskGeometry
, sizeof(DISK_GEOMETRY
));
6675 deviceExtension
->DiskGeometry
->BytesPerSector
= 2048;
6676 deviceExtension
->SectorShift
= 11;
6677 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(0x7fffffff);
6678 deviceExtension
->DiskGeometry
->MediaType
= RemovableMedia
;
6683 // Free resources held.
6686 ExFreePool(srb
->SenseInfoBuffer
);
6687 ExFreePool(srb
->DataBuffer
);
6689 if (Irp
->MdlAddress
) {
6690 IoFreeMdl(Irp
->MdlAddress
);
6693 if (originalIrp
->Tail
.Overlay
.Thread
) {
6695 DebugPrint((2, "CdRomUpdateCapacityCompletion: [%lx] completing original IRP\n", originalIrp
));
6696 IoCompleteRequest(originalIrp
, IO_DISK_INCREMENT
);
6699 DebugPrint((1, "CdRomUpdateCapacityCompletion: [%lx] original irp has "
6706 // It's now safe to either start the next request or let the waiting ioctl
6707 // request continue along it's merry way
6710 IoStartNextPacket(DeviceObject
, FALSE
);
6712 return STATUS_MORE_PROCESSING_REQUIRED
;
6717 CdRomUpdateCapacity(
6718 IN PDEVICE_EXTENSION DeviceExtension
,
6719 IN PIRP IrpToComplete
,
6720 IN OPTIONAL PKEVENT IoctlEvent
6725 Routine Description:
6727 This routine updates the capacity of the disk as recorded in the device extension.
6728 It also completes the IRP given with STATUS_VERIFY_REQUIRED. This routine is called
6729 when a media change has occurred and it is necessary to determine the capacity of the
6730 new media prior to the next access.
6734 DeviceExtension - the device to update
6735 IrpToComplete - the request that needs to be completed when done.
6746 PSCSI_REQUEST_BLOCK srb
;
6747 PREAD_CAPACITY_DATA capacityBuffer
;
6748 PIO_STACK_LOCATION irpStack
;
6752 irp
= IoAllocateIrp((CCHAR
)(DeviceExtension
->DeviceObject
->StackSize
+1),
6757 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
6759 capacityBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
6760 sizeof(READ_CAPACITY_DATA
));
6762 if (capacityBuffer
) {
6765 senseBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
6769 irp
->MdlAddress
= IoAllocateMdl(capacityBuffer
,
6770 sizeof(READ_CAPACITY_DATA
),
6775 if (irp
->MdlAddress
) {
6778 // Have all resources. Set up the IRP to send for the capacity.
6781 IoSetNextIrpStackLocation(irp
);
6782 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
6783 irp
->IoStatus
.Information
= 0;
6785 irp
->UserBuffer
= NULL
;
6788 // Save the device object and retry count in a private stack location.
6791 irpStack
= IoGetCurrentIrpStackLocation(irp
);
6792 irpStack
->DeviceObject
= DeviceExtension
->DeviceObject
;
6793 irpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
6794 irpStack
->Parameters
.Others
.Argument2
= (PVOID
) IrpToComplete
;
6797 // Construct the IRP stack for the lower level driver.
6800 irpStack
= IoGetNextIrpStackLocation(irp
);
6801 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
6802 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
6803 irpStack
->Parameters
.Scsi
.Srb
= srb
;
6804 IoSetCompletionRoutine(irp
,
6805 CdRomUpdateGeometryCompletion
,
6814 MmBuildMdlForNonPagedPool(irp
->MdlAddress
);
6818 // Set up the SRB for read capacity.
6821 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
6822 RtlZeroMemory(senseBuffer
, SENSE_BUFFER_SIZE
);
6823 srb
->CdbLength
= 10;
6824 srb
->TimeOutValue
= DeviceExtension
->TimeOutValue
;
6825 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
6827 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
6828 srb
->PathId
= DeviceExtension
->PathId
;
6829 srb
->TargetId
= DeviceExtension
->TargetId
;
6830 srb
->Lun
= DeviceExtension
->Lun
;
6831 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
6832 srb
->SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
6833 srb
->DataBuffer
= capacityBuffer
;
6834 srb
->DataTransferLength
= sizeof(READ_CAPACITY_DATA
);
6835 srb
->OriginalRequest
= irp
;
6836 srb
->SenseInfoBuffer
= senseBuffer
;
6837 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
6843 cdb
= (PCDB
) &srb
->Cdb
[0];
6844 cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
6845 cdb
->CDB10
.LogicalUnitNumber
= DeviceExtension
->Lun
;
6848 // Set the return value in the IRP that will be completed
6849 // upon completion of the read capacity.
6852 IrpToComplete
->IoStatus
.Status
= STATUS_VERIFY_REQUIRED
;
6853 IoMarkIrpPending(IrpToComplete
);
6855 status
= IoCallDriver(DeviceExtension
->PortDeviceObject
, irp
);
6858 // status is not checked because the completion routine for this
6859 // IRP will always get called and it will free the resources.
6862 return STATUS_PENDING
;
6865 ExFreePool(senseBuffer
);
6866 ExFreePool(capacityBuffer
);
6871 ExFreePool(capacityBuffer
);
6884 return STATUS_INSUFFICIENT_RESOURCES
;
6889 CdRomClassIoctlCompletion(
6890 IN PDEVICE_OBJECT DeviceObject
,
6897 Routine Description:
6899 This routine signals the event used by CdRomDeviceControl to synchronize
6900 class driver (and lower level driver) ioctls with cdrom's startio routine.
6901 The irp completion is short-circuited so that CdRomDeviceControl can
6902 reissue it once it wakes up.
6906 DeviceObject - the device object
6907 Irp - the request we are synchronizing
6908 Context - a PKEVENT that we need to signal
6917 PKEVENT syncEvent
= (PKEVENT
) Context
;
6919 DebugPrint((2, "CdRomClassIoctlCompletion: setting event for irp %#08lx\n",
6923 KeSetEvent(syncEvent
, IO_DISK_INCREMENT
, FALSE
);
6925 return STATUS_MORE_PROCESSING_REQUIRED
;