2 * PROJECT: ReactOS Storage Stack
3 * LICENSE: DDK - see license.txt in the root dir
4 * FILE: drivers/storage/cdrom/cdrom.c
5 * PURPOSE: CDROM driver
6 * PROGRAMMERS: Based on a source code sample from Microsoft NT4 DDK
15 #include <include/class2.h>
21 #define CDB12GENERIC_LENGTH 12
23 typedef struct _XA_CONTEXT
{
26 // Pointer to the device object.
29 PDEVICE_OBJECT DeviceObject
;
32 // Pointer to the original request when
33 // a mode select must be sent.
39 // Pointer to the mode select srb.
42 PSCSI_REQUEST_BLOCK Srb
;
43 } XA_CONTEXT
, *PXA_CONTEXT
;
45 typedef struct _ERROR_RECOVERY_DATA
{
46 MODE_PARAMETER_HEADER Header
;
47 MODE_PARAMETER_BLOCK BlockDescriptor
;
48 MODE_READ_RECOVERY_PAGE ReadRecoveryPage
;
49 } ERROR_RECOVERY_DATA
, *PERROR_RECOVERY_DATA
;
51 typedef struct _ERROR_RECOVERY_DATA10
{
52 MODE_PARAMETER_HEADER10 Header10
;
53 MODE_PARAMETER_BLOCK BlockDescriptor10
;
54 MODE_READ_RECOVERY_PAGE ReadRecoveryPage10
;
55 } ERROR_RECOVERY_DATA10
, *PERROR_RECOVERY_DATA10
;
58 // CdRom specific addition to device extension.
61 typedef struct _CDROM_DATA
{
64 // Indicates whether an audio play operation
65 // is currently being performed.
71 // Indicates whether the blocksize used for user data
78 // Indicates whether 6 or 10 byte mode sense/select
85 // Storage for the error recovery page. This is used
86 // as an easy method to switch block sizes.
90 ERROR_RECOVERY_DATA u1
;
91 ERROR_RECOVERY_DATA10 u2
;
96 // Pointer to the original irp for the raw read.
102 // Used to protect accesses to the RawAccess flag.
105 KSPIN_LOCK FormSpinLock
;
108 // Even if media change support is requested, there are some devices
109 // that are not supported. This flag will indicate that such a device
110 // is present when it is FALSE.
113 BOOLEAN MediaChangeSupported
;
116 // The media change event is being supported. The media change timer
117 // should be running whenever this is true.
123 // The timer value to support media change events. This is a countdown
124 // value used to determine when to poll the device for a media change.
125 // The max value for the timer is 255 seconds.
128 UCHAR MediaChangeCountDown
;
132 // Second timer to keep track of how long the media change IRP has been
133 // in use. If this value exceeds the timeout (#defined) then we should
134 // print out a message to the user and set the MediaChangeIrpLost flag
137 SHORT MediaChangeIrpTimeInUse
;
140 // Set by CdRomTickHandler when we determine that the media change irp has
144 BOOLEAN MediaChangeIrpLost
;
147 UCHAR PadReserve
; // use this for new flags.
150 // An IRP is allocated and kept for the duration that media change
151 // detection is in effect. If this is NULL and MediaChange is TRUE,
152 // the detection is in progress. This should always be NULL when
153 // MediaChange is FALSE.
159 // The timer work list is a collection of IRPS that are prepared for
160 // submission, but need to allow some time to pass before they are
164 LIST_ENTRY TimerIrpList
;
165 KSPIN_LOCK TimerIrpSpinLock
;
167 } CDROM_DATA
, *PCDROM_DATA
;
169 #define DEVICE_EXTENSION_SIZE sizeof(DEVICE_EXTENSION) + sizeof(CDROM_DATA)
170 #define SCSI_CDROM_TIMEOUT 10
171 #define SCSI_CHANGER_BONUS_TIMEOUT 10
172 #define HITACHI_MODE_DATA_SIZE 12
173 #define MODE_DATA_SIZE 64
174 #define RAW_SECTOR_SIZE 2352
175 #define COOKED_SECTOR_SIZE 2048
176 #define MEDIA_CHANGE_DEFAULT_TIME 4
177 #define CDROM_SRB_LIST_SIZE 4
183 // Used to detect the loss of the autorun irp. The driver prints out a message
184 // (debug level 0) if this timeout ever occurs
186 #define MEDIA_CHANGE_TIMEOUT_TIME 300
190 #define PLAY_ACTIVE(DeviceExtension) (((PCDROM_DATA)(DeviceExtension + 1))->PlayActive)
192 #define MSF_TO_LBA(Minutes,Seconds,Frames) \
193 (ULONG)((60 * 75 * (Minutes)) + (75 * (Seconds)) + ((Frames) - 150))
195 #define LBA_TO_MSF(Lba,Minutes,Seconds,Frames) \
197 (Minutes) = (UCHAR)(Lba / (60 * 75)); \
198 (Seconds) = (UCHAR)((Lba % (60 * 75)) / 75); \
199 (Frames) = (UCHAR)((Lba % (60 * 75)) % 75); \
202 #define DEC_TO_BCD(x) (((x / 10) << 4) + (x % 10))
205 // Define flags for XA, CDDA, and Mode Select/Sense
208 #define XA_USE_6_BYTE 0x01
209 #define XA_USE_10_BYTE 0x02
210 #define XA_USE_READ_CD 0x04
211 #define XA_NOT_SUPPORTED 0x08
213 #define PLEXTOR_CDDA 0x10
214 #define NEC_CDDA 0x20
217 // Sector types for READ_CD
221 #define CD_DA_SECTOR 1
222 #define YELLOW_MODE1_SECTOR 2
223 #define YELLOW_MODE2_SECTOR 3
224 #define FORM2_MODE1_SECTOR 4
225 #define FORM2_MODE2_SECTOR 5
229 #ifdef ExAllocatePool
230 #undef ExAllocatePool
232 #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'CscS')
238 IN PDRIVER_OBJECT DriverObject
,
239 IN PUNICODE_STRING RegistryPath
244 ScsiCdRomFindDevices(
245 IN PDRIVER_OBJECT DriverObject
,
246 IN PUNICODE_STRING RegistryPath
,
247 IN PCLASS_INIT_DATA InitializationData
,
248 IN PDEVICE_OBJECT PortDeviceObject
,
255 IN PDEVICE_OBJECT DeviceObject
,
261 ScsiCdRomReadVerification(
262 IN PDEVICE_OBJECT DeviceObject
,
269 IN PDEVICE_OBJECT DeviceObject
,
271 IN PIRP OriginalRequest
277 IN PDEVICE_OBJECT DeviceObject
,
281 IO_COMPLETION_ROUTINE CdRomDeviceControlCompletion
;
284 CdRomDeviceControlCompletion(
285 IN PDEVICE_OBJECT DeviceObject
,
290 IO_COMPLETION_ROUTINE CdRomSetVolumeIntermediateCompletion
;
293 CdRomSetVolumeIntermediateCompletion(
294 IN PDEVICE_OBJECT DeviceObject
,
299 IO_COMPLETION_ROUTINE CdRomSwitchModeCompletion
;
302 CdRomSwitchModeCompletion(
303 IN PDEVICE_OBJECT DeviceObject
,
308 IO_COMPLETION_ROUTINE CdRomXACompletion
;
312 IN PDEVICE_OBJECT DeviceObject
,
317 IO_COMPLETION_ROUTINE CdRomClassIoctlCompletion
;
320 CdRomClassIoctlCompletion(
321 IN PDEVICE_OBJECT DeviceObject
,
329 IN PDEVICE_OBJECT DeviceObject
,
336 IN PDEVICE_OBJECT DeviceObject
,
342 CdRomCheckRegistryForMediaChangeValue(
343 IN PUNICODE_STRING RegistryPath
,
344 IN ULONG DeviceNumber
350 IN PDEVICE_EXTENSION DeviceExtension
,
351 IN PIRP IrpToComplete
,
352 IN OPTIONAL PKEVENT IoctlEvent
357 CreateCdRomDeviceObject(
358 IN PDRIVER_OBJECT DriverObject
,
359 IN PDEVICE_OBJECT PortDeviceObject
,
361 IN PULONG DeviceCount
,
362 PIO_SCSI_CAPABILITIES PortCapabilities
,
363 IN PSCSI_INQUIRY_DATA LunInfo
,
364 IN PCLASS_INIT_DATA InitializationData
,
365 IN PUNICODE_STRING RegistryPath
371 PDEVICE_OBJECT DeviceObject
,
372 PINQUIRYDATA InquiryData
,
373 PIO_SCSI_CAPABILITIES PortCapabilities
379 IN PDEVICE_OBJECT DeviceObject
385 PDEVICE_OBJECT DeviceObject
,
386 PSCSI_REQUEST_BLOCK Srb
,
391 IO_COMPLETION_ROUTINE ToshibaProcessErrorCompletion
;
395 PDEVICE_OBJECT DeviceObject
,
396 PSCSI_REQUEST_BLOCK Srb
,
403 IsThisAnAtapiChanger(
404 IN PDEVICE_OBJECT DeviceObject
,
405 OUT PULONG DiscsPresent
411 IN PDEVICE_OBJECT DeviceObject
,
418 IsThisAMultiLunDevice(
419 IN PDEVICE_OBJECT DeviceObject
,
420 IN PDEVICE_OBJECT PortDeviceObject
425 CdRomCreateNamedEvent(
426 IN PDEVICE_EXTENSION DeviceExtension
,
427 IN ULONG DeviceNumber
434 IN UNICODE_STRING ScsiUnicodeString
[],
435 OUT PUCHAR IntermediateController
440 #pragma alloc_text(PAGE, DriverEntry)
441 #pragma alloc_text(PAGE, ScsiCdRomFindDevices)
442 #pragma alloc_text(PAGE, CreateCdRomDeviceObject)
443 #pragma alloc_text(PAGE, ScanForSpecial)
444 //#pragma alloc_text(PAGE, CdRomDeviceControl)
445 #pragma alloc_text(PAGE, HitachProcessError)
446 #pragma alloc_text(PAGE, CdRomIsPlayActive)
447 #pragma alloc_text(PAGE, ScsiCdRomReadVerification)
448 #pragma alloc_text(INIT, CdRomCheckRegistryForMediaChangeValue)
449 #pragma alloc_text(INIT, IsThisAnAtapiChanger)
450 #pragma alloc_text(INIT, IsThisASanyo)
451 #pragma alloc_text(INIT, IsThisAMultiLunDevice)
452 #pragma alloc_text(INIT, CdRomCreateNamedEvent)
454 #pragma alloc_text(PAGE, FindScsiAdapter)
463 IN PDRIVER_OBJECT DriverObject
,
464 IN PUNICODE_STRING RegistryPath
471 This routine initializes the cdrom class driver.
475 DriverObject - Pointer to driver object created by system.
477 RegistryPath - Pointer to the name of the services node for this driver.
481 The function value is the final status from the initialization operation.
486 CLASS_INIT_DATA InitializationData
;
489 return STATUS_NO_SUCH_DEVICE
;
496 RtlZeroMemory (&InitializationData
, sizeof(CLASS_INIT_DATA
));
502 InitializationData
.InitializationDataSize
= sizeof(CLASS_INIT_DATA
);
503 InitializationData
.DeviceExtensionSize
= DEVICE_EXTENSION_SIZE
;
505 InitializationData
.DeviceType
= FILE_DEVICE_CD_ROM
;
506 InitializationData
.DeviceCharacteristics
= FILE_REMOVABLE_MEDIA
| FILE_READ_ONLY_DEVICE
;
512 InitializationData
.ClassReadWriteVerification
= ScsiCdRomReadVerification
;
513 InitializationData
.ClassDeviceControl
= CdRomDeviceControl
;
514 InitializationData
.ClassFindDevices
= ScsiCdRomFindDevices
;
515 InitializationData
.ClassShutdownFlush
= NULL
;
516 InitializationData
.ClassCreateClose
= NULL
;
517 InitializationData
.ClassStartIo
= ScsiCdRomStartIo
;
520 // Call the class init routine
523 return ScsiClassInitialize( DriverObject
, RegistryPath
, &InitializationData
);
525 } // end DriverEntry()
529 ScsiCdRomFindDevices(
530 IN PDRIVER_OBJECT DriverObject
,
531 IN PUNICODE_STRING RegistryPath
,
532 IN PCLASS_INIT_DATA InitializationData
,
533 IN PDEVICE_OBJECT PortDeviceObject
,
541 Connect to SCSI port driver. Get adapter capabilities and
542 SCSI bus configuration information. Search inquiry data
543 for CDROM devices to process.
547 DriverObject - CDROM class driver object.
548 PortDeviceObject - SCSI port driver device object.
549 PortNumber - The system ordinal for this scsi adapter.
553 TRUE if CDROM device present on this SCSI adapter.
558 PIO_SCSI_CAPABILITIES portCapabilities
;
561 PSCSI_INQUIRY_DATA lunInfo
;
562 PSCSI_ADAPTER_BUS_INFO adapterInfo
;
563 PINQUIRYDATA inquiryData
;
566 BOOLEAN foundDevice
= FALSE
;
569 // Call port driver to get adapter capabilities.
572 status
= ScsiClassGetCapabilities(PortDeviceObject
, &portCapabilities
);
574 if (!NT_SUCCESS(status
)) {
575 DebugPrint((1,"FindScsiDevices: ScsiClassGetCapabilities failed\n"));
580 // Call port driver to get inquiry information to find cdroms.
583 status
= ScsiClassGetInquiryData(PortDeviceObject
, (PSCSI_ADAPTER_BUS_INFO
*) &buffer
);
585 if (!NT_SUCCESS(status
)) {
586 DebugPrint((1,"FindScsiDevices: ScsiClassGetInquiryData failed\n"));
591 // Get the address of the count of the number of cdroms already initialized.
594 cdRomCount
= &IoGetConfigurationInformation()->CdRomCount
;
595 adapterInfo
= (PVOID
) buffer
;
598 // For each SCSI bus this adapter supports ...
601 for (scsiBus
=0; scsiBus
< adapterInfo
->NumberOfBuses
; scsiBus
++) {
604 // Get the SCSI bus scan data for this bus.
607 lunInfo
= (PVOID
) (buffer
+ adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
);
610 // Search list for unclaimed disk devices.
613 while (adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
) {
615 inquiryData
= (PVOID
)lunInfo
->InquiryData
;
617 if ((inquiryData
->DeviceType
== READ_ONLY_DIRECT_ACCESS_DEVICE
) &&
618 (inquiryData
->DeviceTypeQualifier
== 0) &&
619 (!lunInfo
->DeviceClaimed
)) {
621 DebugPrint((1,"FindScsiDevices: Vendor string is %.24s\n",
622 inquiryData
->VendorId
));
625 // Create device objects for cdrom
628 status
= CreateCdRomDeviceObject(DriverObject
,
637 if (NT_SUCCESS(status
)) {
640 // Increment system cdrom device count.
646 // Indicate that a cdrom device was found.
657 if (lunInfo
->NextInquiryDataOffset
== 0) {
661 lunInfo
= (PVOID
) (buffer
+ lunInfo
->NextInquiryDataOffset
);
670 } // end FindScsiCdRoms()
674 CdRomCreateNamedEvent(
675 IN PDEVICE_EXTENSION DeviceExtension
,
676 IN ULONG DeviceNumber
683 Create the named synchronization event for notification of media change
684 events to the system. The event is reset before this function returns.
688 DeviceExtension - the device extension pointer for storage of the event pointer.
697 UNICODE_STRING unicodeString
;
698 OBJECT_ATTRIBUTES objectAttributes
;
699 CCHAR eventNameBuffer
[MAXIMUM_FILENAME_LENGTH
];
700 STRING eventNameString
;
705 sprintf(eventNameBuffer
,"\\Device\\MediaChangeEvent%ld",
708 RtlInitString(&eventNameString
,
711 status
= RtlAnsiStringToUnicodeString(&unicodeString
,
715 if (!NT_SUCCESS(status
)) {
719 InitializeObjectAttributes(&objectAttributes
,
721 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
725 DeviceExtension
->MediaChangeEvent
= IoCreateSynchronizationEvent(&unicodeString
,
727 DeviceExtension
->MediaChangeEventHandle
= handle
;
729 KeClearEvent(DeviceExtension
->MediaChangeEvent
);
731 RtlFreeUnicodeString(&unicodeString
);
736 CreateCdRomDeviceObject(
737 IN PDRIVER_OBJECT DriverObject
,
738 IN PDEVICE_OBJECT PortDeviceObject
,
740 IN PULONG DeviceCount
,
741 IN PIO_SCSI_CAPABILITIES PortCapabilities
,
742 IN PSCSI_INQUIRY_DATA LunInfo
,
743 IN PCLASS_INIT_DATA InitializationData
,
744 IN PUNICODE_STRING RegistryPath
751 This routine creates an object for the device and then calls the
752 SCSI port driver for media capacity and sector size.
756 DriverObject - Pointer to driver object created by system.
757 PortDeviceObject - to connect to SCSI port driver.
758 DeviceCount - Number of previously installed CDROMs.
759 PortCapabilities - Pointer to structure returned by SCSI port
760 driver describing adapter capabilities (and limitations).
761 LunInfo - Pointer to configuration information for this device.
769 CHAR ntNameBuffer
[64];
771 BOOLEAN changerDevice
;
772 SCSI_REQUEST_BLOCK srb
;
776 PVOID senseData
= NULL
;
777 PDEVICE_OBJECT deviceObject
= NULL
;
778 PDEVICE_EXTENSION deviceExtension
= NULL
;
783 BOOLEAN srbListInitialized
= FALSE
;
786 // Claim the device. Note that any errors after this
787 // will goto the generic handler, where the device will
791 status
= ScsiClassClaimDevice(PortDeviceObject
,
796 if (!NT_SUCCESS(status
)) {
801 // Create device object for this device.
804 sprintf(ntNameBuffer
,
805 "\\Device\\CdRom%lu",
808 status
= ScsiClassCreateDeviceObject(DriverObject
,
814 if (!NT_SUCCESS(status
)) {
815 DebugPrint((1,"CreateCdRomDeviceObjects: Can not create device %s\n",
818 goto CreateCdRomDeviceObjectExit
;
822 // Indicate that IRPs should include MDLs.
825 deviceObject
->Flags
|= DO_DIRECT_IO
;
828 // Set up required stack size in device object.
831 deviceObject
->StackSize
= PortDeviceObject
->StackSize
+ 2;
833 deviceExtension
= deviceObject
->DeviceExtension
;
836 // Allocate spinlock for split request completion.
839 KeInitializeSpinLock(&deviceExtension
->SplitRequestSpinLock
);
842 // This is the physical device.
845 deviceExtension
->PhysicalDevice
= deviceObject
;
848 // Initialize lock count to zero. The lock count is used to
849 // disable the ejection mechanism when media is mounted.
852 deviceExtension
->LockCount
= 0;
855 // Save system cdrom number
858 deviceExtension
->DeviceNumber
= *DeviceCount
;
861 // Copy port device object to device extension.
864 deviceExtension
->PortDeviceObject
= PortDeviceObject
;
867 // Set the alignment requirements for the device based on the
868 // host adapter requirements
871 if (PortDeviceObject
->AlignmentRequirement
> deviceObject
->AlignmentRequirement
) {
872 deviceObject
->AlignmentRequirement
= PortDeviceObject
->AlignmentRequirement
;
876 // Save address of port driver capabilities.
879 deviceExtension
->PortCapabilities
= PortCapabilities
;
885 deviceExtension
->SrbFlags
= 0;
886 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
889 // Allocate request sense buffer.
892 senseData
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
894 if (senseData
== NULL
) {
897 // The buffer cannot be allocated.
900 status
= STATUS_INSUFFICIENT_RESOURCES
;
901 goto CreateCdRomDeviceObjectExit
;
905 // Set the sense data pointer in the device extension.
908 deviceExtension
->SenseData
= senseData
;
911 // CDROMs are not partitionable so starting offset is 0.
914 deviceExtension
->StartingOffset
.LowPart
= 0;
915 deviceExtension
->StartingOffset
.HighPart
= 0;
918 // Path/TargetId/LUN describes a device location on the SCSI bus.
919 // This information comes from the LunInfo buffer.
922 deviceExtension
->PortNumber
= (UCHAR
)PortNumber
;
923 deviceExtension
->PathId
= LunInfo
->PathId
;
924 deviceExtension
->TargetId
= LunInfo
->TargetId
;
925 deviceExtension
->Lun
= LunInfo
->Lun
;
928 // Set timeout value in seconds.
931 timeOut
= ScsiClassQueryTimeOutRegistryValue(RegistryPath
);
933 deviceExtension
->TimeOutValue
= timeOut
;
935 deviceExtension
->TimeOutValue
= SCSI_CDROM_TIMEOUT
;
939 // Build the lookaside list for srb's for the physical disk. Should only
943 ScsiClassInitializeSrbLookasideList(deviceExtension
,
944 CDROM_SRB_LIST_SIZE
);
946 srbListInitialized
= TRUE
;
949 // Back pointer to device object.
952 deviceExtension
->DeviceObject
= deviceObject
;
955 // Allocate buffer for drive geometry.
958 deviceExtension
->DiskGeometry
=
959 ExAllocatePool(NonPagedPool
, sizeof(DISK_GEOMETRY_EX
));
961 if (deviceExtension
->DiskGeometry
== NULL
) {
963 status
= STATUS_INSUFFICIENT_RESOURCES
;
964 goto CreateCdRomDeviceObjectExit
;
968 // Set up media change support defaults.
971 cddata
= (PCDROM_DATA
)(deviceExtension
+ 1);
973 KeInitializeSpinLock(&cddata
->FormSpinLock
);
974 KeInitializeSpinLock(&cddata
->TimerIrpSpinLock
);
975 InitializeListHead(&cddata
->TimerIrpList
);
977 cddata
->MediaChangeCountDown
= MEDIA_CHANGE_DEFAULT_TIME
;
978 cddata
->MediaChangeSupported
= FALSE
;
979 cddata
->MediaChange
= FALSE
;
982 // Assume that there is initially no media in the device
983 // only notify upper layers if there is something there
986 deviceExtension
->MediaChangeNoMedia
= TRUE
;
987 cddata
->MediaChangeIrp
= NULL
;
989 cddata
->MediaChangeIrpTimeInUse
= 0;
990 cddata
->MediaChangeIrpLost
= FALSE
;
994 // Scan for Scsi controllers that require special processing.
997 ScanForSpecial(deviceObject
,
998 (PINQUIRYDATA
) LunInfo
->InquiryData
,
1002 // Do READ CAPACITY. This SCSI command
1003 // returns the last sector address on the device
1004 // and the bytes per sector.
1005 // These are used to calculate the drive capacity
1009 status
= ScsiClassReadDriveCapacity(deviceObject
);
1010 bps
= deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
;
1012 if (!NT_SUCCESS(status
) || !bps
) {
1015 "CreateCdRomDeviceObjects: Can't read capacity for device %s\n",
1019 // Set disk geometry to default values (per ISO 9660).
1023 deviceExtension
->SectorShift
= 11;
1024 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(0x7fffffff);
1028 // Insure that bytes per sector is a power of 2
1029 // This corrects a problem with the HP 4020i CDR where it
1030 // returns an incorrect number for bytes per sector.
1033 lastBit
= (ULONG
) -1;
1041 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= bps
;
1042 DebugPrint((2, "CreateCdRomDeviceObject: Calc'd bps = %x\n", bps
));
1045 // Check to see if this is some sort of changer device
1048 changerDevice
= FALSE
;
1051 // Search for devices that have special requirements for media
1055 if (deviceExtension
->Lun
> 0) {
1056 changerDevice
= TRUE
;
1059 if (!changerDevice
) {
1060 changerDevice
= IsThisASanyo(deviceObject
, deviceExtension
->PathId
,
1061 deviceExtension
->TargetId
);
1064 if (!changerDevice
) {
1066 changerDevice
= IsThisAnAtapiChanger(deviceObject
, &tmp
);
1069 if (!changerDevice
) {
1070 changerDevice
= IsThisAMultiLunDevice(deviceObject
, PortDeviceObject
);
1074 // If it is a changer device, increment the timeout to take platter-swapping
1075 // time into account
1079 deviceExtension
->TimeOutValue
+= SCSI_CHANGER_BONUS_TIMEOUT
;
1083 // Create the media change named event. If this succeeds then continue
1084 // initializing the media change support data items.
1087 CdRomCreateNamedEvent(deviceExtension
,*DeviceCount
);
1088 if (deviceExtension
->MediaChangeEvent
) {
1091 // If this is not a changer, get an IRP for the timer request
1092 // and initialize the timer.
1095 if (!changerDevice
) {
1098 // Not a changer device - continue with media change initialization.
1099 // Determine if the user actually wants media change events.
1102 if (CdRomCheckRegistryForMediaChangeValue(RegistryPath
, *DeviceCount
)) {
1103 PIO_STACK_LOCATION irpStack
;
1104 PSCSI_REQUEST_BLOCK srb
;
1108 // User wants it - preallocate IRP and SRB.
1111 irp
= IoAllocateIrp((CCHAR
)(deviceObject
->StackSize
+1),
1116 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
1117 buffer
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
1119 if (srb
&& buffer
) {
1123 // All resources have been allocated set up the IRP.
1126 IoSetNextIrpStackLocation(irp
);
1127 irpStack
= IoGetCurrentIrpStackLocation(irp
);
1128 irpStack
->DeviceObject
= deviceObject
;
1129 irpStack
= IoGetNextIrpStackLocation(irp
);
1130 cddata
->MediaChangeIrp
= irp
;
1131 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1134 // Initialize the SRB
1137 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
1140 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
* 2;
1141 srb
->QueueTag
= SP_UNTAGGED
;
1142 srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
1143 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1144 srb
->PathId
= deviceExtension
->PathId
;
1145 srb
->TargetId
= deviceExtension
->TargetId
;
1146 srb
->Lun
= deviceExtension
->Lun
;
1147 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1150 // Initialize and set up the sense information buffer
1153 RtlZeroMemory(buffer
, SENSE_BUFFER_SIZE
);
1154 srb
->SenseInfoBuffer
= buffer
;
1155 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1158 // Initialize the CDB
1161 cdb
= (PCDB
)&srb
->Cdb
[0];
1162 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_TEST_UNIT_READY
;
1163 cdb
->CDB6GENERIC
.LogicalUnitNumber
= deviceExtension
->Lun
;
1166 // It is ok to support media change events on this device.
1169 cddata
->MediaChangeSupported
= TRUE
;
1170 cddata
->MediaChange
= TRUE
;
1184 deviceExtension
->MediaChangeEvent
= NULL
;
1187 deviceExtension
->MediaChangeEvent
= NULL
;
1192 // Assume use of 6-byte mode sense/select for now.
1195 cddata
->XAFlags
|= XA_USE_6_BYTE
;
1198 // Build and issue mode sense with Read error recovery page. This will be used to change
1199 // block size in case of any raw reads (Mode 2, Form 2).
1202 length
= (sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH
);
1204 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
1207 cdb
= (PCDB
)srb
.Cdb
;
1210 // Set timeout value from device extension.
1213 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
1216 // Build the MODE SENSE CDB. The data returned will be kept in the device extension
1217 // and used to set block size.
1220 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
1221 cdb
->MODE_SENSE
.PageCode
= 0x1;
1222 cdb
->MODE_SENSE
.AllocationLength
= (UCHAR
)length
;
1224 buffer
= ExAllocatePool(NonPagedPoolCacheAligned
, (sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH10
));
1226 status
= STATUS_INSUFFICIENT_RESOURCES
;
1227 goto CreateCdRomDeviceObjectExit
;
1230 status
= ScsiClassSendSrbSynchronous(deviceObject
,
1235 if (!NT_SUCCESS(status
)) {
1238 // May be Atapi, try 10-byte.
1241 length
= (sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH10
);
1243 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
1246 // Build the MODE SENSE CDB.
1250 cdb
= (PCDB
)srb
.Cdb
;
1253 // Set timeout value from device extension.
1256 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
1258 cdb
->MODE_SENSE10
.OperationCode
= SCSIOP_MODE_SENSE10
;
1259 cdb
->MODE_SENSE10
.PageCode
= 0x1;
1261 cdb
->MODE_SENSE10
.AllocationLength
[0] = (UCHAR
)(length
>> 8);
1262 cdb
->MODE_SENSE10
.AllocationLength
[1] = (UCHAR
)(length
& 0xFF);
1264 status
= ScsiClassSendSrbSynchronous(deviceObject
,
1269 if (status
== STATUS_DATA_OVERRUN
) {
1272 // Build and issue the ReadCd command to ensure that this device supports it.
1275 RtlZeroMemory(cdb
, 12);
1277 cdb
->READ_CD
.OperationCode
= SCSIOP_READ_CD
;
1279 status
= ScsiClassSendSrbSynchronous(deviceObject
,
1286 // If the command wasn't rejected then support the READ_CD.
1289 if (NT_SUCCESS(status
) || (status
== STATUS_NO_MEDIA_IN_DEVICE
)) {
1292 // Using Read CD precludes issuing a mode select to
1293 // set the user data size. So, no buffer copy is
1297 cddata
->XAFlags
&= ~XA_USE_6_BYTE
;
1298 cddata
->XAFlags
|= XA_USE_READ_CD
| XA_USE_10_BYTE
;
1301 RtlCopyMemory(&cddata
->u1
.Header
, buffer
, sizeof(ERROR_RECOVERY_DATA10
));
1302 cddata
->u1
.Header
.ModeDataLength
= 0;
1304 cddata
->XAFlags
&= ~XA_USE_6_BYTE
;
1305 cddata
->XAFlags
|= XA_USE_10_BYTE
;
1308 } else if (NT_SUCCESS(status
)) {
1310 RtlCopyMemory(&cddata
->u1
.Header
, buffer
, sizeof(ERROR_RECOVERY_DATA10
));
1311 cddata
->u1
.Header
.ModeDataLength
= 0;
1313 cddata
->XAFlags
&= ~XA_USE_6_BYTE
;
1314 cddata
->XAFlags
|= XA_USE_10_BYTE
;
1317 cddata
->XAFlags
|= XA_NOT_SUPPORTED
;
1320 RtlCopyMemory(&cddata
->u1
.Header
, buffer
, sizeof(ERROR_RECOVERY_DATA
));
1321 cddata
->u1
.Header
.ModeDataLength
= 0;
1327 // Start the timer now regardless of if Autorun is enabled.
1328 // The timer must run forever since IoStopTimer faults.
1331 IoInitializeTimer(deviceObject
, CdRomTickHandler
, NULL
);
1332 IoStartTimer(deviceObject
);
1334 return(STATUS_SUCCESS
);
1336 CreateCdRomDeviceObjectExit
:
1339 // Release the device since an error occured.
1342 ScsiClassClaimDevice(PortDeviceObject
,
1347 if (senseData
!= NULL
) {
1348 ExFreePool(senseData
);
1351 if (deviceExtension
->DiskGeometry
!= NULL
) {
1352 ExFreePool(deviceExtension
->DiskGeometry
);
1355 if (deviceObject
!= NULL
) {
1356 if (srbListInitialized
) {
1357 ExDeleteNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
);
1359 IoDeleteDevice(deviceObject
);
1365 } // end CreateCdRomDeviceObject()
1370 IN PDEVICE_OBJECT DeviceObject
,
1375 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1376 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1377 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
1378 PIO_STACK_LOCATION irpStack
;
1380 ULONG transferPages
;
1381 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
1382 ULONG maximumTransferLength
= deviceExtension
->PortCapabilities
->MaximumTransferLength
;
1384 PSCSI_REQUEST_BLOCK srb
= NULL
;
1386 PUCHAR senseBuffer
= NULL
;
1392 // Mark IRP with status pending.
1395 IoMarkIrpPending(Irp
);
1398 // If the flag is set in the device object, force a verify.
1401 if (DeviceObject
->Flags
& DO_VERIFY_VOLUME
) {
1402 DebugPrint((2, "ScsiCdRomStartIo: [%lx] Volume needs verified\n", Irp
));
1403 if (!(currentIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
)) {
1405 if (Irp
->Tail
.Overlay
.Thread
) {
1406 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
1409 Irp
->IoStatus
.Status
= STATUS_VERIFY_REQUIRED
;
1411 DebugPrint((2, "ScsiCdRomStartIo: [%lx] Calling UpdateCapacity - "
1412 "ioctl event = %lx\n",
1414 nextIrpStack
->Parameters
.Others
.Argument1
1418 // our device control dispatch routine stores an event in the next
1419 // stack location to signal when startio has completed. We need to
1420 // pass this in so that the update capacity completion routine can
1421 // set it rather than completing the Irp.
1424 status
= CdRomUpdateCapacity(deviceExtension
,
1426 nextIrpStack
->Parameters
.Others
.Argument1
1429 DebugPrint((2, "ScsiCdRomStartIo: [%lx] UpdateCapacity returned %lx\n", Irp
, status
));
1430 ASSERT(status
== STATUS_PENDING
);
1435 cdData
= (PCDROM_DATA
)(deviceExtension
+ 1);
1436 use6Byte
= cdData
->XAFlags
& XA_USE_6_BYTE
;
1438 if (currentIrpStack
->MajorFunction
== IRP_MJ_READ
) {
1441 // Add partition byte offset to make starting byte relative to
1442 // beginning of disk. In addition, add in skew for DM Driver, if any.
1445 currentIrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+= (deviceExtension
->StartingOffset
.QuadPart
);
1448 // Calculate number of pages in this transfer.
1451 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp
->MdlAddress
),
1452 currentIrpStack
->Parameters
.Read
.Length
);
1455 // Check if request length is greater than the maximum number of
1456 // bytes that the hardware can transfer.
1459 if (cdData
->RawAccess
) {
1461 ASSERT(!(cdData
->XAFlags
& XA_USE_READ_CD
));
1464 // Fire off a mode select to switch back to cooked sectors.
1467 irp2
= IoAllocateIrp((CCHAR
)(deviceExtension
->DeviceObject
->StackSize
+1),
1471 Irp
->IoStatus
.Information
= 0;
1472 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1473 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1474 IoStartNextPacket(DeviceObject
, FALSE
);
1478 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
1480 Irp
->IoStatus
.Information
= 0;
1481 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1482 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1484 IoStartNextPacket(DeviceObject
, FALSE
);
1488 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
1490 cdb
= (PCDB
)srb
->Cdb
;
1493 // Allocate sense buffer.
1496 senseBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
1499 Irp
->IoStatus
.Information
= 0;
1500 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1501 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1504 IoStartNextPacket(DeviceObject
, FALSE
);
1512 IoSetNextIrpStackLocation(irp2
);
1513 irp2
->IoStatus
.Status
= STATUS_SUCCESS
;
1514 irp2
->IoStatus
.Information
= 0;
1516 irp2
->UserBuffer
= NULL
;
1519 // Save the device object and irp in a private stack location.
1522 irpStack
= IoGetCurrentIrpStackLocation(irp2
);
1523 irpStack
->DeviceObject
= deviceExtension
->DeviceObject
;
1524 irpStack
->Parameters
.Others
.Argument2
= (PVOID
) Irp
;
1527 // The retry count will be in the real Irp, as the retry logic will
1528 // recreate our private irp.
1531 if (!(nextIrpStack
->Parameters
.Others
.Argument1
)) {
1534 // Only jam this in if it doesn't exist. The completion routines can
1535 // call StartIo directly in the case of retries and resetting it will
1536 // cause infinite loops.
1539 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
1543 // Construct the IRP stack for the lower level driver.
1546 irpStack
= IoGetNextIrpStackLocation(irp2
);
1547 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
1548 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
1549 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1551 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1552 srb
->PathId
= deviceExtension
->PathId
;
1553 srb
->TargetId
= deviceExtension
->TargetId
;
1554 srb
->Lun
= deviceExtension
->Lun
;
1555 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1556 srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
1557 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
1559 srb
->OriginalRequest
= irp2
;
1560 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1561 srb
->SenseInfoBuffer
= senseBuffer
;
1563 transferByteCount
= (use6Byte
) ? sizeof(ERROR_RECOVERY_DATA
) : sizeof(ERROR_RECOVERY_DATA10
);
1564 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, transferByteCount
);
1566 Irp
->IoStatus
.Information
= 0;
1567 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1568 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1569 ExFreePool(senseBuffer
);
1572 IoStartNextPacket(DeviceObject
, FALSE
);
1577 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
1583 if (!irp2
->MdlAddress
) {
1584 Irp
->IoStatus
.Information
= 0;
1585 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1586 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1587 ExFreePool(senseBuffer
);
1589 ExFreePool(dataBuffer
);
1591 IoStartNextPacket(DeviceObject
, FALSE
);
1599 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
1601 srb
->DataBuffer
= dataBuffer
;
1604 // Set the new block size in the descriptor.
1607 cdData
->u1
.BlockDescriptor
.BlockLength
[0] = (UCHAR
)(COOKED_SECTOR_SIZE
>> 16) & 0xFF;
1608 cdData
->u1
.BlockDescriptor
.BlockLength
[1] = (UCHAR
)(COOKED_SECTOR_SIZE
>> 8) & 0xFF;
1609 cdData
->u1
.BlockDescriptor
.BlockLength
[2] = (UCHAR
)(COOKED_SECTOR_SIZE
& 0xFF);
1612 // Move error page into dataBuffer.
1615 RtlCopyMemory(srb
->DataBuffer
, &cdData
->u1
.Header
, transferByteCount
);
1618 // Build and send a mode select to switch into raw mode.
1621 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
1622 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_OUT
);
1623 srb
->DataTransferLength
= transferByteCount
;
1624 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
* 2;
1628 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
1629 cdb
->MODE_SELECT
.PFBit
= 1;
1630 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)transferByteCount
;
1633 srb
->CdbLength
= 10;
1634 cdb
->MODE_SELECT10
.OperationCode
= SCSIOP_MODE_SELECT10
;
1635 cdb
->MODE_SELECT10
.PFBit
= 1;
1636 cdb
->MODE_SELECT10
.ParameterListLength
[0] = (UCHAR
)(transferByteCount
>> 8);
1637 cdb
->MODE_SELECT10
.ParameterListLength
[1] = (UCHAR
)(transferByteCount
& 0xFF);
1641 // Update completion routine.
1644 IoSetCompletionRoutine(irp2
,
1645 CdRomSwitchModeCompletion
,
1651 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
1655 if ((currentIrpStack
->Parameters
.Read
.Length
> maximumTransferLength
) ||
1657 deviceExtension
->PortCapabilities
->MaximumPhysicalPages
)) {
1660 // Request needs to be split. Completion of each portion of the
1661 // request will fire off the next portion. The final request will
1662 // signal Io to send a new request.
1666 deviceExtension
->PortCapabilities
->MaximumPhysicalPages
- 1;
1668 if(maximumTransferLength
> transferPages
<< PAGE_SHIFT
) {
1669 maximumTransferLength
= transferPages
<< PAGE_SHIFT
;
1673 // Check that the maximum transfer size is not zero
1676 if(maximumTransferLength
== 0) {
1677 maximumTransferLength
= PAGE_SIZE
;
1680 ScsiClassSplitRequest(DeviceObject
, Irp
, maximumTransferLength
);
1686 // Build SRB and CDB for this IRP.
1689 ScsiClassBuildRequest(DeviceObject
, Irp
);
1694 } else if (currentIrpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
) {
1697 // Allocate an irp, srb and associated structures.
1700 irp2
= IoAllocateIrp((CCHAR
)(deviceExtension
->DeviceObject
->StackSize
+1),
1704 Irp
->IoStatus
.Information
= 0;
1705 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1706 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1707 IoStartNextPacket(DeviceObject
, FALSE
);
1708 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp
, Irp
->IoStatus
.Status
, __LINE__
));
1712 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
1714 Irp
->IoStatus
.Information
= 0;
1715 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1716 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1718 IoStartNextPacket(DeviceObject
, FALSE
);
1719 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp
, Irp
->IoStatus
.Status
, __LINE__
));
1723 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
1725 cdb
= (PCDB
)srb
->Cdb
;
1728 // Allocate sense buffer.
1731 senseBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
1734 Irp
->IoStatus
.Information
= 0;
1735 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1736 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1739 IoStartNextPacket(DeviceObject
, FALSE
);
1740 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp
, Irp
->IoStatus
.Status
, __LINE__
));
1748 IoSetNextIrpStackLocation(irp2
);
1749 irp2
->IoStatus
.Status
= STATUS_SUCCESS
;
1750 irp2
->IoStatus
.Information
= 0;
1752 irp2
->UserBuffer
= NULL
;
1755 // Save the device object and irp in a private stack location.
1758 irpStack
= IoGetCurrentIrpStackLocation(irp2
);
1759 irpStack
->DeviceObject
= deviceExtension
->DeviceObject
;
1760 irpStack
->Parameters
.Others
.Argument2
= (PVOID
) Irp
;
1763 // The retry count will be in the real Irp, as the retry logic will
1764 // recreate our private irp.
1767 if (!(nextIrpStack
->Parameters
.Others
.Argument1
)) {
1770 // Only jam this in if it doesn't exist. The completion routines can
1771 // call StartIo directly in the case of retries and resetting it will
1772 // cause infinite loops.
1775 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
1779 // Construct the IRP stack for the lower level driver.
1782 irpStack
= IoGetNextIrpStackLocation(irp2
);
1783 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
1784 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
1785 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1787 IoSetCompletionRoutine(irp2
,
1788 CdRomDeviceControlCompletion
,
1794 // Setup those fields that are generic to all requests.
1797 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1798 srb
->PathId
= deviceExtension
->PathId
;
1799 srb
->TargetId
= deviceExtension
->TargetId
;
1800 srb
->Lun
= deviceExtension
->Lun
;
1801 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1802 srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
1803 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
1805 srb
->OriginalRequest
= irp2
;
1806 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1807 srb
->SenseInfoBuffer
= senseBuffer
;
1809 switch (currentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
) {
1811 case IOCTL_CDROM_RAW_READ
: {
1814 // Determine whether the drive is currently in raw or cooked mode,
1815 // and which command to use to read the data.
1818 if (!(cdData
->XAFlags
& XA_USE_READ_CD
)) {
1820 PRAW_READ_INFO rawReadInfo
=
1821 (PRAW_READ_INFO
)currentIrpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
1822 ULONG maximumTransferLength
;
1823 ULONG transferPages
;
1825 if (cdData
->RawAccess
) {
1827 ULONG startingSector
;
1830 // Free the recently allocated irp, as we don't need it.
1835 cdb
= (PCDB
)srb
->Cdb
;
1836 RtlZeroMemory(cdb
, 12);
1839 // Calculate starting offset.
1842 startingSector
= (ULONG
)(rawReadInfo
->DiskOffset
.QuadPart
>> deviceExtension
->SectorShift
);
1843 transferByteCount
= rawReadInfo
->SectorCount
* RAW_SECTOR_SIZE
;
1844 maximumTransferLength
= deviceExtension
->PortCapabilities
->MaximumTransferLength
;
1845 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp
->MdlAddress
),
1849 // Determine if request is within limits imposed by miniport.
1852 if (transferByteCount
> maximumTransferLength
||
1853 transferPages
> deviceExtension
->PortCapabilities
->MaximumPhysicalPages
) {
1856 // The claim is that this won't happen, and is backed up by
1857 // ActiveMovie usage, which does unbuffered XA reads of 0x18000, yet
1858 // we get only 4 sector requests.
1862 Irp
->IoStatus
.Information
= 0;
1863 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
1864 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1865 ExFreePool(senseBuffer
);
1867 IoStartNextPacket(DeviceObject
, FALSE
);
1872 srb
->OriginalRequest
= Irp
;
1873 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
1874 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
1875 srb
->DataTransferLength
= transferByteCount
;
1876 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
1877 srb
->CdbLength
= 10;
1878 srb
->DataBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
1880 if (rawReadInfo
->TrackMode
== CDDA
) {
1881 if (cdData
->XAFlags
& PLEXTOR_CDDA
) {
1883 srb
->CdbLength
= 12;
1885 cdb
->PLXTR_READ_CDDA
.LogicalUnitNumber
= deviceExtension
->Lun
;
1886 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
1887 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
1888 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
1889 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
1891 cdb
->PLXTR_READ_CDDA
.TransferBlockByte3
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
1892 cdb
->PLXTR_READ_CDDA
.TransferBlockByte2
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
1893 cdb
->PLXTR_READ_CDDA
.TransferBlockByte1
= 0;
1894 cdb
->PLXTR_READ_CDDA
.TransferBlockByte0
= 0;
1896 cdb
->PLXTR_READ_CDDA
.SubCode
= 0;
1897 cdb
->PLXTR_READ_CDDA
.OperationCode
= 0xD8;
1899 } else if (cdData
->XAFlags
& NEC_CDDA
) {
1901 cdb
->NEC_READ_CDDA
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
1902 cdb
->NEC_READ_CDDA
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
1903 cdb
->NEC_READ_CDDA
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
1904 cdb
->NEC_READ_CDDA
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
1906 cdb
->NEC_READ_CDDA
.TransferBlockByte1
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
1907 cdb
->NEC_READ_CDDA
.TransferBlockByte0
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
1909 cdb
->NEC_READ_CDDA
.OperationCode
= 0xD4;
1913 cdb
->CDB10
.LogicalUnitNumber
= deviceExtension
->Lun
;
1915 cdb
->CDB10
.TransferBlocksMsb
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
1916 cdb
->CDB10
.TransferBlocksLsb
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
1918 cdb
->CDB10
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
1919 cdb
->CDB10
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
1920 cdb
->CDB10
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
1921 cdb
->CDB10
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
1923 cdb
->CDB10
.OperationCode
= SCSIOP_READ
;
1926 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
1928 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
1929 nextIrpStack
->Parameters
.Scsi
.Srb
= srb
;
1931 if (!(nextIrpStack
->Parameters
.Others
.Argument1
)) {
1934 // Only jam this in if it doesn't exist. The completion routines can
1935 // call StartIo directly in the case of retries and resetting it will
1936 // cause infinite loops.
1939 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
1943 // Set up IoCompletion routine address.
1946 IoSetCompletionRoutine(Irp
,
1953 IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
1958 transferByteCount
= (use6Byte
) ? sizeof(ERROR_RECOVERY_DATA
) : sizeof(ERROR_RECOVERY_DATA10
);
1959 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, transferByteCount
);
1961 Irp
->IoStatus
.Information
= 0;
1962 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1963 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1964 ExFreePool(senseBuffer
);
1967 IoStartNextPacket(DeviceObject
, FALSE
);
1972 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
1978 if (!irp2
->MdlAddress
) {
1979 Irp
->IoStatus
.Information
= 0;
1980 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1981 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1982 ExFreePool(senseBuffer
);
1984 ExFreePool(dataBuffer
);
1986 IoStartNextPacket(DeviceObject
, FALSE
);
1994 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
1996 srb
->DataBuffer
= dataBuffer
;
1999 // Set the new block size in the descriptor.
2002 cdData
->u1
.BlockDescriptor
.BlockLength
[0] = (UCHAR
)(RAW_SECTOR_SIZE
>> 16) & 0xFF;
2003 cdData
->u1
.BlockDescriptor
.BlockLength
[1] = (UCHAR
)(RAW_SECTOR_SIZE
>> 8) & 0xFF;
2004 cdData
->u1
.BlockDescriptor
.BlockLength
[2] = (UCHAR
)(RAW_SECTOR_SIZE
& 0xFF);
2008 // TODO: Set density code, based on operation
2011 cdData
->u1
.BlockDescriptor
.DensityCode
= 0;
2015 // Move error page into dataBuffer.
2018 RtlCopyMemory(srb
->DataBuffer
, &cdData
->u1
.Header
, transferByteCount
);
2022 // Build and send a mode select to switch into raw mode.
2025 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2026 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_OUT
);
2027 srb
->DataTransferLength
= transferByteCount
;
2028 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
* 2;
2032 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
2033 cdb
->MODE_SELECT
.PFBit
= 1;
2034 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)transferByteCount
;
2037 srb
->CdbLength
= 10;
2038 cdb
->MODE_SELECT10
.OperationCode
= SCSIOP_MODE_SELECT10
;
2039 cdb
->MODE_SELECT10
.PFBit
= 1;
2040 cdb
->MODE_SELECT10
.ParameterListLength
[0] = (UCHAR
)(transferByteCount
>> 8);
2041 cdb
->MODE_SELECT10
.ParameterListLength
[1] = (UCHAR
)(transferByteCount
& 0xFF);
2045 // Update completion routine.
2048 IoSetCompletionRoutine(irp2
,
2049 CdRomSwitchModeCompletion
,
2059 PRAW_READ_INFO rawReadInfo
=
2060 (PRAW_READ_INFO
)currentIrpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
2061 ULONG startingSector
;
2064 // Free the recently allocated irp, as we don't need it.
2069 cdb
= (PCDB
)srb
->Cdb
;
2070 RtlZeroMemory(cdb
, 12);
2074 // Calculate starting offset.
2077 startingSector
= (ULONG
)(rawReadInfo
->DiskOffset
.QuadPart
>> deviceExtension
->SectorShift
);
2078 transferByteCount
= rawReadInfo
->SectorCount
* RAW_SECTOR_SIZE
;
2081 srb
->OriginalRequest
= Irp
;
2082 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2083 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
2084 srb
->DataTransferLength
= transferByteCount
;
2085 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2086 srb
->DataBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
2087 srb
->CdbLength
= 12;
2088 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
2091 // Fill in CDB fields.
2094 cdb
= (PCDB
)srb
->Cdb
;
2097 cdb
->READ_CD
.TransferBlocks
[2] = (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
2098 cdb
->READ_CD
.TransferBlocks
[1] = (UCHAR
) (rawReadInfo
->SectorCount
>> 8 );
2099 cdb
->READ_CD
.TransferBlocks
[0] = (UCHAR
) (rawReadInfo
->SectorCount
>> 16);
2102 cdb
->READ_CD
.StartingLBA
[3] = (UCHAR
) (startingSector
& 0xFF);
2103 cdb
->READ_CD
.StartingLBA
[2] = (UCHAR
) ((startingSector
>> 8));
2104 cdb
->READ_CD
.StartingLBA
[1] = (UCHAR
) ((startingSector
>> 16));
2105 cdb
->READ_CD
.StartingLBA
[0] = (UCHAR
) ((startingSector
>> 24));
2108 // Setup cdb depending upon the sector type we want.
2111 switch (rawReadInfo
->TrackMode
) {
2114 cdb
->READ_CD
.ExpectedSectorType
= CD_DA_SECTOR
;
2115 cdb
->READ_CD
.IncludeUserData
= 1;
2116 cdb
->READ_CD
.HeaderCode
= 3;
2117 cdb
->READ_CD
.IncludeSyncData
= 1;
2122 cdb
->READ_CD
.ExpectedSectorType
= YELLOW_MODE2_SECTOR
;
2123 cdb
->READ_CD
.IncludeUserData
= 1;
2124 cdb
->READ_CD
.HeaderCode
= 1;
2125 cdb
->READ_CD
.IncludeSyncData
= 1;
2130 cdb
->READ_CD
.ExpectedSectorType
= FORM2_MODE2_SECTOR
;
2131 cdb
->READ_CD
.IncludeUserData
= 1;
2132 cdb
->READ_CD
.HeaderCode
= 3;
2133 cdb
->READ_CD
.IncludeSyncData
= 1;
2137 Irp
->IoStatus
.Information
= 0;
2138 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
2139 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2140 ExFreePool(senseBuffer
);
2142 IoStartNextPacket(DeviceObject
, FALSE
);
2143 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp
, Irp
->IoStatus
.Status
, __LINE__
));
2147 cdb
->READ_CD
.OperationCode
= SCSIOP_READ_CD
;
2149 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
2150 nextIrpStack
->Parameters
.Scsi
.Srb
= srb
;
2152 if (!(nextIrpStack
->Parameters
.Others
.Argument1
)) {
2155 // Only jam this in if it doesn't exist. The completion routines can
2156 // call StartIo directly in the case of retries and resetting it will
2157 // cause infinite loops.
2160 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
2164 // Set up IoCompletion routine address.
2167 IoSetCompletionRoutine(Irp
,
2174 IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
2179 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2183 case IOCTL_DISK_GET_LENGTH_INFO
:
2184 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX
:
2185 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
2186 case IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX
:
2187 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
: {
2190 // Issue ReadCapacity to update device extension
2191 // with information for current media.
2195 "CdRomStartIo: Get drive capacity\n"));
2198 // setup remaining srb and cdb parameters.
2201 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2202 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
2203 srb
->DataTransferLength
= sizeof(READ_CAPACITY_DATA
);
2204 srb
->CdbLength
= 10;
2205 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2207 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, sizeof(READ_CAPACITY_DATA
));
2209 Irp
->IoStatus
.Information
= 0;
2210 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2211 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2212 ExFreePool(senseBuffer
);
2215 IoStartNextPacket(DeviceObject
, FALSE
);
2216 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp
, Irp
->IoStatus
.Status
, __LINE__
));
2221 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2222 sizeof(READ_CAPACITY_DATA
),
2227 if (!irp2
->MdlAddress
) {
2228 Irp
->IoStatus
.Information
= 0;
2229 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2230 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2231 ExFreePool(senseBuffer
);
2233 ExFreePool(dataBuffer
);
2235 IoStartNextPacket(DeviceObject
, FALSE
);
2236 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp
, Irp
->IoStatus
.Status
, __LINE__
));
2244 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2246 srb
->DataBuffer
= dataBuffer
;
2247 cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
2249 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2253 case IOCTL_CDROM_CHECK_VERIFY
: {
2256 // Since a test unit ready is about to be performed, reset the timer
2257 // value to decrease the opportunities for it to race with this code.
2260 cdData
->MediaChangeCountDown
= MEDIA_CHANGE_DEFAULT_TIME
;
2263 // Set up the SRB/CDB
2267 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_TEST_UNIT_READY
;
2268 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
* 2;
2269 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2270 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_NO_DATA_TRANSFER
);
2272 DebugPrint((2, "ScsiCdRomStartIo: [%lx] Sending CHECK_VERIFY irp %lx\n", Irp
, irp2
));
2273 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2277 case IOCTL_CDROM_GET_LAST_SESSION
:
2280 // Set format to return first and last session numbers.
2283 cdb
->READ_TOC
.Format
= GET_LAST_SESSION
;
2286 // Fall through to READ TOC code.
2289 case IOCTL_CDROM_READ_TOC
: {
2292 if (currentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_READ_TOC
) {
2295 // Use MSF addressing if not request for session information.
2298 cdb
->READ_TOC
.Msf
= CDB_USE_MSF
;
2302 // Set size of TOC structure.
2306 currentIrpStack
->Parameters
.Read
.Length
>
2307 sizeof(CDROM_TOC
) ? sizeof(CDROM_TOC
):
2308 currentIrpStack
->Parameters
.Read
.Length
;
2310 cdb
->READ_TOC
.AllocationLength
[0] = (UCHAR
) (transferByteCount
>> 8);
2311 cdb
->READ_TOC
.AllocationLength
[1] = (UCHAR
) (transferByteCount
& 0xFF);
2313 cdb
->READ_TOC
.Control
= 0;
2316 // Start at beginning of disc.
2319 cdb
->READ_TOC
.StartingTrack
= 0;
2322 // setup remaining srb and cdb parameters.
2325 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2326 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
2327 srb
->DataTransferLength
= transferByteCount
;
2328 srb
->CdbLength
= 10;
2329 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2331 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, transferByteCount
);
2333 Irp
->IoStatus
.Information
= 0;
2334 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2335 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2336 ExFreePool(senseBuffer
);
2339 IoStartNextPacket(DeviceObject
, FALSE
);
2344 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2350 if (!irp2
->MdlAddress
) {
2351 Irp
->IoStatus
.Information
= 0;
2352 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2353 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2354 ExFreePool(senseBuffer
);
2356 ExFreePool(dataBuffer
);
2358 IoStartNextPacket(DeviceObject
, FALSE
);
2366 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2368 srb
->DataBuffer
= dataBuffer
;
2369 cdb
->READ_TOC
.OperationCode
= SCSIOP_READ_TOC
;
2371 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2376 case IOCTL_CDROM_PLAY_AUDIO_MSF
: {
2378 PCDROM_PLAY_AUDIO_MSF inputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
2381 // Set up the SRB/CDB
2384 srb
->CdbLength
= 10;
2385 cdb
->PLAY_AUDIO_MSF
.OperationCode
= SCSIOP_PLAY_AUDIO_MSF
;
2387 cdb
->PLAY_AUDIO_MSF
.StartingM
= inputBuffer
->StartingM
;
2388 cdb
->PLAY_AUDIO_MSF
.StartingS
= inputBuffer
->StartingS
;
2389 cdb
->PLAY_AUDIO_MSF
.StartingF
= inputBuffer
->StartingF
;
2391 cdb
->PLAY_AUDIO_MSF
.EndingM
= inputBuffer
->EndingM
;
2392 cdb
->PLAY_AUDIO_MSF
.EndingS
= inputBuffer
->EndingS
;
2393 cdb
->PLAY_AUDIO_MSF
.EndingF
= inputBuffer
->EndingF
;
2395 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2396 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2397 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_NO_DATA_TRANSFER
);
2399 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2404 case IOCTL_CDROM_READ_Q_CHANNEL
: {
2406 PCDROM_SUB_Q_DATA_FORMAT inputBuffer
=
2407 Irp
->AssociatedIrp
.SystemBuffer
;
2410 // Allocate buffer for subq channel information.
2413 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
2414 sizeof(SUB_Q_CHANNEL_DATA
));
2417 Irp
->IoStatus
.Information
= 0;
2418 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2419 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2420 ExFreePool(senseBuffer
);
2423 IoStartNextPacket(DeviceObject
, FALSE
);
2428 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2434 if (!irp2
->MdlAddress
) {
2435 Irp
->IoStatus
.Information
= 0;
2436 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2437 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2438 ExFreePool(senseBuffer
);
2440 ExFreePool(dataBuffer
);
2442 IoStartNextPacket(DeviceObject
, FALSE
);
2450 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2452 srb
->DataBuffer
= dataBuffer
;
2455 // Always logical unit 0, but only use MSF addressing
2456 // for IOCTL_CDROM_CURRENT_POSITION
2459 if (inputBuffer
->Format
==IOCTL_CDROM_CURRENT_POSITION
)
2460 cdb
->SUBCHANNEL
.Msf
= CDB_USE_MSF
;
2463 // Return subchannel data
2466 cdb
->SUBCHANNEL
.SubQ
= CDB_SUBCHANNEL_BLOCK
;
2469 // Specify format of information to return
2472 cdb
->SUBCHANNEL
.Format
= inputBuffer
->Format
;
2475 // Specify which track to access (only used by Track ISRC reads)
2478 if (inputBuffer
->Format
==IOCTL_CDROM_TRACK_ISRC
) {
2479 cdb
->SUBCHANNEL
.TrackNumber
= inputBuffer
->Track
;
2483 // Set size of channel data -- however, this is dependent on
2484 // what information we are requesting (which Format)
2487 switch( inputBuffer
->Format
) {
2489 case IOCTL_CDROM_CURRENT_POSITION
:
2490 transferByteCount
= sizeof(SUB_Q_CURRENT_POSITION
);
2493 case IOCTL_CDROM_MEDIA_CATALOG
:
2494 transferByteCount
= sizeof(SUB_Q_MEDIA_CATALOG_NUMBER
);
2497 case IOCTL_CDROM_TRACK_ISRC
:
2498 transferByteCount
= sizeof(SUB_Q_TRACK_ISRC
);
2502 cdb
->SUBCHANNEL
.AllocationLength
[0] = (UCHAR
) (transferByteCount
>> 8);
2503 cdb
->SUBCHANNEL
.AllocationLength
[1] = (UCHAR
) (transferByteCount
& 0xFF);
2504 cdb
->SUBCHANNEL
.OperationCode
= SCSIOP_READ_SUB_CHANNEL
;
2505 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2506 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
2507 srb
->DataTransferLength
= transferByteCount
;
2508 srb
->CdbLength
= 10;
2509 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2511 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2516 case IOCTL_CDROM_PAUSE_AUDIO
: {
2518 cdb
->PAUSE_RESUME
.OperationCode
= SCSIOP_PAUSE_RESUME
;
2519 cdb
->PAUSE_RESUME
.Action
= CDB_AUDIO_PAUSE
;
2521 srb
->CdbLength
= 10;
2522 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2523 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2524 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_NO_DATA_TRANSFER
);
2526 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2530 case IOCTL_CDROM_RESUME_AUDIO
: {
2532 cdb
->PAUSE_RESUME
.OperationCode
= SCSIOP_PAUSE_RESUME
;
2533 cdb
->PAUSE_RESUME
.Action
= CDB_AUDIO_RESUME
;
2535 srb
->CdbLength
= 10;
2536 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2537 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2538 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_NO_DATA_TRANSFER
);
2540 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2544 case IOCTL_CDROM_SEEK_AUDIO_MSF
: {
2546 PCDROM_SEEK_AUDIO_MSF inputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
2547 ULONG logicalBlockAddress
;
2549 logicalBlockAddress
= MSF_TO_LBA(inputBuffer
->M
, inputBuffer
->S
, inputBuffer
->F
);
2551 cdb
->SEEK
.OperationCode
= SCSIOP_SEEK
;
2552 cdb
->SEEK
.LogicalBlockAddress
[0] = ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte3
;
2553 cdb
->SEEK
.LogicalBlockAddress
[1] = ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte2
;
2554 cdb
->SEEK
.LogicalBlockAddress
[2] = ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte1
;
2555 cdb
->SEEK
.LogicalBlockAddress
[3] = ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte0
;
2557 srb
->CdbLength
= 10;
2558 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2559 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2560 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_NO_DATA_TRANSFER
);
2562 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2567 case IOCTL_CDROM_STOP_AUDIO
: {
2569 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
2570 cdb
->START_STOP
.Immediate
= 1;
2571 cdb
->START_STOP
.Start
= 0;
2572 cdb
->START_STOP
.LoadEject
= 0;
2575 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2577 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2578 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_NO_DATA_TRANSFER
);
2580 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2584 case IOCTL_CDROM_GET_CONTROL
: {
2586 // Allocate buffer for volume control information.
2589 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
2593 Irp
->IoStatus
.Information
= 0;
2594 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2595 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2596 ExFreePool(senseBuffer
);
2599 IoStartNextPacket(DeviceObject
, FALSE
);
2604 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2610 if (!irp2
->MdlAddress
) {
2611 Irp
->IoStatus
.Information
= 0;
2612 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2613 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2614 ExFreePool(senseBuffer
);
2616 ExFreePool(dataBuffer
);
2618 IoStartNextPacket(DeviceObject
, FALSE
);
2626 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2627 srb
->DataBuffer
= dataBuffer
;
2629 RtlZeroMemory(dataBuffer
, MODE_DATA_SIZE
);
2632 // Setup for either 6 or 10 byte CDBs.
2637 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
2638 cdb
->MODE_SENSE
.PageCode
= CDROM_AUDIO_CONTROL_PAGE
;
2639 cdb
->MODE_SENSE
.AllocationLength
= MODE_DATA_SIZE
;
2642 // Disable block descriptors.
2645 cdb
->MODE_SENSE
.Dbd
= TRUE
;
2650 cdb
->MODE_SENSE10
.OperationCode
= SCSIOP_MODE_SENSE10
;
2651 cdb
->MODE_SENSE10
.PageCode
= CDROM_AUDIO_CONTROL_PAGE
;
2652 cdb
->MODE_SENSE10
.AllocationLength
[0] = (UCHAR
)(MODE_DATA_SIZE
>> 8);
2653 cdb
->MODE_SENSE10
.AllocationLength
[1] = (UCHAR
)(MODE_DATA_SIZE
& 0xFF);
2656 // Disable block descriptors.
2659 cdb
->MODE_SENSE10
.Dbd
= TRUE
;
2661 srb
->CdbLength
= 10;
2664 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2665 srb
->DataTransferLength
= MODE_DATA_SIZE
;
2666 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2667 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
2669 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2674 case IOCTL_CDROM_GET_VOLUME
:
2675 case IOCTL_CDROM_SET_VOLUME
: {
2677 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
2681 Irp
->IoStatus
.Information
= 0;
2682 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2683 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2684 ExFreePool(senseBuffer
);
2687 IoStartNextPacket(DeviceObject
, FALSE
);
2691 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2697 if (!irp2
->MdlAddress
) {
2698 Irp
->IoStatus
.Information
= 0;
2699 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2700 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2701 ExFreePool(senseBuffer
);
2703 ExFreePool(dataBuffer
);
2705 IoStartNextPacket(DeviceObject
, FALSE
);
2713 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2714 srb
->DataBuffer
= dataBuffer
;
2716 RtlZeroMemory(dataBuffer
, MODE_DATA_SIZE
);
2720 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
2721 cdb
->MODE_SENSE
.PageCode
= CDROM_AUDIO_CONTROL_PAGE
;
2722 cdb
->MODE_SENSE
.AllocationLength
= MODE_DATA_SIZE
;
2728 cdb
->MODE_SENSE10
.OperationCode
= SCSIOP_MODE_SENSE10
;
2729 cdb
->MODE_SENSE10
.PageCode
= CDROM_AUDIO_CONTROL_PAGE
;
2730 cdb
->MODE_SENSE10
.AllocationLength
[0] = (UCHAR
)(MODE_DATA_SIZE
>> 8);
2731 cdb
->MODE_SENSE10
.AllocationLength
[1] = (UCHAR
)(MODE_DATA_SIZE
& 0xFF);
2733 srb
->CdbLength
= 10;
2736 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2737 srb
->DataTransferLength
= MODE_DATA_SIZE
;
2738 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2739 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
2741 if (currentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_SET_VOLUME
) {
2744 // Setup a different completion routine as the mode sense data is needed in order
2745 // to send the mode select.
2748 IoSetCompletionRoutine(irp2
,
2749 CdRomSetVolumeIntermediateCompletion
,
2757 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2765 // Just complete the request - CdRomClassIoctlCompletion will take
2766 // care of it for us
2769 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2770 ExFreePool(senseBuffer
);
2779 // If a read or an unhandled IRP_MJ_XX, end up here. The unhandled IRP_MJ's
2780 // are expected and composed of AutoRun Irps, at present.
2783 IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
2790 ScsiCdRomReadVerification(
2791 IN PDEVICE_OBJECT DeviceObject
,
2797 Routine Description:
2799 This is the entry called by the I/O system for read requests.
2800 It builds the SRB and sends it to the port driver.
2804 DeviceObject - the system object for the device.
2814 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2815 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
2816 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
2817 LARGE_INTEGER startingOffset
= currentIrpStack
->Parameters
.Read
.ByteOffset
;
2820 // If the cd is playing music then reject this request.
2823 if (PLAY_ACTIVE(deviceExtension
)) {
2824 Irp
->IoStatus
.Status
= STATUS_DEVICE_BUSY
;
2825 return STATUS_DEVICE_BUSY
;
2829 // Verify parameters of this request.
2830 // Check that ending sector is on disc and
2831 // that number of bytes to transfer is a multiple of
2835 startingOffset
.QuadPart
= currentIrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+
2838 if (!deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
) {
2839 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= 2048;
2842 if ((startingOffset
.QuadPart
> deviceExtension
->PartitionLength
.QuadPart
) ||
2843 (transferByteCount
& (deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
- 1))) {
2845 DebugPrint((1,"ScsiCdRomRead: Invalid I/O parameters\n"));
2846 DebugPrint((1, "\toffset %x:%x, Length %x:%x\n",
2847 startingOffset
.u
.HighPart
,
2848 startingOffset
.u
.LowPart
,
2849 deviceExtension
->PartitionLength
.u
.HighPart
,
2850 deviceExtension
->PartitionLength
.u
.LowPart
));
2851 DebugPrint((1, "\tbps %x\n", deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
));
2854 // Fail request with status of invalid parameters.
2857 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
2859 return STATUS_INVALID_PARAMETER
;
2863 return STATUS_SUCCESS
;
2865 } // end ScsiCdRomReadVerification()
2870 CdRomDeviceControlCompletion(
2871 IN PDEVICE_OBJECT DeviceObject
,
2876 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2877 PDEVICE_EXTENSION physicalExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
2878 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
2879 PCDROM_DATA cdData
= (PCDROM_DATA
)(deviceExtension
+ 1);
2880 BOOLEAN use6Byte
= cdData
->XAFlags
& XA_USE_6_BYTE
;
2881 PIO_STACK_LOCATION realIrpStack
;
2882 PIO_STACK_LOCATION realIrpNextStack
;
2883 PSCSI_REQUEST_BLOCK srb
= Context
;
2884 PIRP realIrp
= NULL
;
2889 // Extract the 'real' irp from the irpstack.
2892 realIrp
= (PIRP
) irpStack
->Parameters
.Others
.Argument2
;
2893 realIrpStack
= IoGetCurrentIrpStackLocation(realIrp
);
2894 realIrpNextStack
= IoGetNextIrpStackLocation(realIrp
);
2897 // Check SRB status for success of completing request.
2900 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
2903 "CdRomDeviceControlCompletion: Irp %lx, Srb %lx Real Irp %lx Status %lx\n",
2910 // Release the queue if it is frozen.
2913 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
2914 DebugPrint((2, "CdRomDeviceControlCompletion: Releasing Queue\n"));
2915 ScsiClassReleaseQueue(DeviceObject
);
2919 retry
= ScsiClassInterpretSenseInfo(DeviceObject
,
2921 irpStack
->MajorFunction
,
2922 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
,
2923 MAXIMUM_RETRIES
- ((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
),
2926 DebugPrint((2, "CdRomDeviceControlCompletion: IRP will %sbe retried\n",
2927 (retry
? "" : "not ")));
2930 // Some of the Device Controls need special cases on non-Success status's.
2933 if (realIrpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
) {
2934 if ((realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_GET_LAST_SESSION
) ||
2935 (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_READ_TOC
) ||
2936 (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_GET_CONTROL
) ||
2937 (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_GET_VOLUME
)) {
2939 if (status
== STATUS_DATA_OVERRUN
) {
2940 status
= STATUS_SUCCESS
;
2945 if (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_READ_Q_CHANNEL
) {
2946 PLAY_ACTIVE(deviceExtension
) = FALSE
;
2951 // If the status is verified required and the this request
2952 // should bypass verify required then retry the request.
2955 if (realIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
2956 status
== STATUS_VERIFY_REQUIRED
) {
2958 if (((realIrpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
) ||
2959 (realIrpStack
->MajorFunction
== IRP_MJ_INTERNAL_DEVICE_CONTROL
)) &&
2960 (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_CHECK_VERIFY
)) {
2962 ExFreePool(srb
->SenseInfoBuffer
);
2963 if (srb
->DataBuffer
) {
2964 ExFreePool(srb
->DataBuffer
);
2967 if (Irp
->MdlAddress
) {
2968 IoFreeMdl(Irp
->MdlAddress
);
2974 // Update the geometry information, as the media could have changed.
2975 // The completion routine for this will complete the real irp and start
2979 status
= CdRomUpdateCapacity(deviceExtension
,realIrp
, NULL
);
2980 DebugPrint((2, "CdRomDeviceControlCompletion: [%lx] CdRomUpdateCapacity completed with status %lx\n", realIrp
, status
));
2981 ASSERT(status
== STATUS_PENDING
);
2983 return STATUS_MORE_PROCESSING_REQUIRED
;
2987 status
= STATUS_IO_DEVICE_ERROR
;
2993 if (retry
&& (realIrpNextStack
->Parameters
.Others
.Argument1
= (PVOID
)((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
-1))) {
2996 if (((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
)) {
3002 DebugPrint((1, "Retry request %lx - Calling StartIo\n", Irp
));
3005 ExFreePool(srb
->SenseInfoBuffer
);
3006 if (srb
->DataBuffer
) {
3007 ExFreePool(srb
->DataBuffer
);
3010 if (Irp
->MdlAddress
) {
3011 IoFreeMdl(Irp
->MdlAddress
);
3017 // Call StartIo directly since IoStartNextPacket hasn't been called,
3018 // the serialisation is still intact.
3021 ScsiCdRomStartIo(DeviceObject
, realIrp
);
3022 return STATUS_MORE_PROCESSING_REQUIRED
;
3027 // Exhausted retries. Fall through and complete the request with the appropriate status.
3034 // Set status for successful request.
3037 status
= STATUS_SUCCESS
;
3040 if (NT_SUCCESS(status
)) {
3042 switch (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
) {
3044 case IOCTL_DISK_GET_LENGTH_INFO
: {
3046 PREAD_CAPACITY_DATA readCapacityBuffer
= srb
->DataBuffer
;
3053 // Swizzle bytes from Read Capacity and translate into
3054 // the necessary geometry information in the device extension.
3057 tmp
= readCapacityBuffer
->BytesPerBlock
;
3058 ((PFOUR_BYTE
)&bps
)->Byte0
= ((PFOUR_BYTE
)&tmp
)->Byte3
;
3059 ((PFOUR_BYTE
)&bps
)->Byte1
= ((PFOUR_BYTE
)&tmp
)->Byte2
;
3060 ((PFOUR_BYTE
)&bps
)->Byte2
= ((PFOUR_BYTE
)&tmp
)->Byte1
;
3061 ((PFOUR_BYTE
)&bps
)->Byte3
= ((PFOUR_BYTE
)&tmp
)->Byte0
;
3064 // Insure that bps is a power of 2.
3065 // This corrects a problem with the HP 4020i CDR where it
3066 // returns an incorrect number for bytes per sector.
3072 lastBit
= (ULONG
) -1;
3080 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= bps
;
3083 "CdRomDeviceControlCompletion: Calculated bps %#x\n",
3084 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
));
3087 // Copy last sector in reverse byte order.
3090 tmp
= readCapacityBuffer
->LogicalBlockAddress
;
3091 ((PFOUR_BYTE
)&lastSector
)->Byte0
= ((PFOUR_BYTE
)&tmp
)->Byte3
;
3092 ((PFOUR_BYTE
)&lastSector
)->Byte1
= ((PFOUR_BYTE
)&tmp
)->Byte2
;
3093 ((PFOUR_BYTE
)&lastSector
)->Byte2
= ((PFOUR_BYTE
)&tmp
)->Byte1
;
3094 ((PFOUR_BYTE
)&lastSector
)->Byte3
= ((PFOUR_BYTE
)&tmp
)->Byte0
;
3097 // Calculate sector to byte shift.
3100 WHICH_BIT(bps
, deviceExtension
->SectorShift
);
3102 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Sector size is %d\n",
3103 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
));
3105 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Number of Sectors is %d\n",
3109 // Calculate media capacity in bytes.
3112 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(lastSector
+ 1);
3115 // Calculate number of cylinders.
3118 deviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
= (LONGLONG
)((lastSector
+ 1)/(32 * 64));
3120 deviceExtension
->PartitionLength
.QuadPart
=
3121 (deviceExtension
->PartitionLength
.QuadPart
<< deviceExtension
->SectorShift
);
3123 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
3126 // This device supports removable media.
3129 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= RemovableMedia
;
3134 // Assume media type is fixed disk.
3137 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= FixedMedia
;
3141 // Assume sectors per track are 32;
3144 deviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
= 32;
3147 // Assume tracks per cylinder (number of heads) is 64.
3150 deviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
= 64;
3153 // Copy the device extension's geometry info into the user buffer.
3156 RtlMoveMemory(realIrp
->AssociatedIrp
.SystemBuffer
,
3157 &deviceExtension
->PartitionLength
,
3158 sizeof(GET_LENGTH_INFORMATION
));
3161 // update information field.
3164 realIrp
->IoStatus
.Information
= sizeof(DISK_GEOMETRY
);
3168 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX
:
3169 case IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX
: {
3171 PREAD_CAPACITY_DATA readCapacityBuffer
= srb
->DataBuffer
;
3176 PDISK_GEOMETRY_EX geometryEx
;
3179 // Swizzle bytes from Read Capacity and translate into
3180 // the necessary geometry information in the device extension.
3183 tmp
= readCapacityBuffer
->BytesPerBlock
;
3184 ((PFOUR_BYTE
)&bps
)->Byte0
= ((PFOUR_BYTE
)&tmp
)->Byte3
;
3185 ((PFOUR_BYTE
)&bps
)->Byte1
= ((PFOUR_BYTE
)&tmp
)->Byte2
;
3186 ((PFOUR_BYTE
)&bps
)->Byte2
= ((PFOUR_BYTE
)&tmp
)->Byte1
;
3187 ((PFOUR_BYTE
)&bps
)->Byte3
= ((PFOUR_BYTE
)&tmp
)->Byte0
;
3190 // Insure that bps is a power of 2.
3191 // This corrects a problem with the HP 4020i CDR where it
3192 // returns an incorrect number for bytes per sector.
3198 lastBit
= (ULONG
) -1;
3206 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= bps
;
3209 "CdRomDeviceControlCompletion: Calculated bps %#x\n",
3210 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
));
3213 // Copy last sector in reverse byte order.
3216 tmp
= readCapacityBuffer
->LogicalBlockAddress
;
3217 ((PFOUR_BYTE
)&lastSector
)->Byte0
= ((PFOUR_BYTE
)&tmp
)->Byte3
;
3218 ((PFOUR_BYTE
)&lastSector
)->Byte1
= ((PFOUR_BYTE
)&tmp
)->Byte2
;
3219 ((PFOUR_BYTE
)&lastSector
)->Byte2
= ((PFOUR_BYTE
)&tmp
)->Byte1
;
3220 ((PFOUR_BYTE
)&lastSector
)->Byte3
= ((PFOUR_BYTE
)&tmp
)->Byte0
;
3223 // Calculate sector to byte shift.
3226 WHICH_BIT(bps
, deviceExtension
->SectorShift
);
3228 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Sector size is %d\n",
3229 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
));
3231 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Number of Sectors is %d\n",
3235 // Calculate media capacity in bytes.
3238 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(lastSector
+ 1);
3241 // Calculate number of cylinders.
3244 deviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
= (LONGLONG
)((lastSector
+ 1)/(32 * 64));
3246 deviceExtension
->PartitionLength
.QuadPart
=
3247 (deviceExtension
->PartitionLength
.QuadPart
<< deviceExtension
->SectorShift
);
3249 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
3252 // This device supports removable media.
3255 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= RemovableMedia
;
3260 // Assume media type is fixed disk.
3263 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= FixedMedia
;
3267 // Assume sectors per track are 32;
3270 deviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
= 32;
3273 // Assume tracks per cylinder (number of heads) is 64.
3276 deviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
= 64;
3279 // Copy the device extension's geometry info into the user buffer.
3282 geometryEx
= realIrp
->AssociatedIrp
.SystemBuffer
;
3283 RtlMoveMemory(&geometryEx
->Geometry
,
3284 &deviceExtension
->DiskGeometry
->Geometry
,
3285 sizeof(DISK_GEOMETRY
));
3288 // Copy the extended information
3291 geometryEx
->DiskSize
= deviceExtension
->PartitionLength
;
3294 // update information field.
3297 realIrp
->IoStatus
.Information
= FIELD_OFFSET(DISK_GEOMETRY_EX
, Data
);
3301 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
3302 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
: {
3304 PREAD_CAPACITY_DATA readCapacityBuffer
= srb
->DataBuffer
;
3311 // Swizzle bytes from Read Capacity and translate into
3312 // the necessary geometry information in the device extension.
3315 tmp
= readCapacityBuffer
->BytesPerBlock
;
3316 ((PFOUR_BYTE
)&bps
)->Byte0
= ((PFOUR_BYTE
)&tmp
)->Byte3
;
3317 ((PFOUR_BYTE
)&bps
)->Byte1
= ((PFOUR_BYTE
)&tmp
)->Byte2
;
3318 ((PFOUR_BYTE
)&bps
)->Byte2
= ((PFOUR_BYTE
)&tmp
)->Byte1
;
3319 ((PFOUR_BYTE
)&bps
)->Byte3
= ((PFOUR_BYTE
)&tmp
)->Byte0
;
3322 // Insure that bps is a power of 2.
3323 // This corrects a problem with the HP 4020i CDR where it
3324 // returns an incorrect number for bytes per sector.
3330 lastBit
= (ULONG
) -1;
3338 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= bps
;
3341 "CdRomDeviceControlCompletion: Calculated bps %#x\n",
3342 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
));
3345 // Copy last sector in reverse byte order.
3348 tmp
= readCapacityBuffer
->LogicalBlockAddress
;
3349 ((PFOUR_BYTE
)&lastSector
)->Byte0
= ((PFOUR_BYTE
)&tmp
)->Byte3
;
3350 ((PFOUR_BYTE
)&lastSector
)->Byte1
= ((PFOUR_BYTE
)&tmp
)->Byte2
;
3351 ((PFOUR_BYTE
)&lastSector
)->Byte2
= ((PFOUR_BYTE
)&tmp
)->Byte1
;
3352 ((PFOUR_BYTE
)&lastSector
)->Byte3
= ((PFOUR_BYTE
)&tmp
)->Byte0
;
3355 // Calculate sector to byte shift.
3358 WHICH_BIT(bps
, deviceExtension
->SectorShift
);
3360 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Sector size is %d\n",
3361 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
));
3363 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Number of Sectors is %d\n",
3367 // Calculate media capacity in bytes.
3370 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(lastSector
+ 1);
3373 // Calculate number of cylinders.
3376 deviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
= (LONGLONG
)((lastSector
+ 1)/(32 * 64));
3378 deviceExtension
->PartitionLength
.QuadPart
=
3379 (deviceExtension
->PartitionLength
.QuadPart
<< deviceExtension
->SectorShift
);
3381 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
3384 // This device supports removable media.
3387 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= RemovableMedia
;
3392 // Assume media type is fixed disk.
3395 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= FixedMedia
;
3399 // Assume sectors per track are 32;
3402 deviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
= 32;
3405 // Assume tracks per cylinder (number of heads) is 64.
3408 deviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
= 64;
3411 // Copy the device extension's geometry info into the user buffer.
3414 RtlMoveMemory(realIrp
->AssociatedIrp
.SystemBuffer
,
3415 deviceExtension
->DiskGeometry
,
3416 sizeof(DISK_GEOMETRY
));
3419 // update information field.
3422 realIrp
->IoStatus
.Information
= sizeof(DISK_GEOMETRY
);
3426 case IOCTL_CDROM_CHECK_VERIFY
:
3428 if((realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_CHECK_VERIFY
) &&
3429 (realIrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
)) {
3431 *((PULONG
)realIrp
->AssociatedIrp
.SystemBuffer
) =
3432 physicalExtension
->MediaChangeCount
;
3433 realIrp
->IoStatus
.Information
= sizeof(ULONG
);
3435 realIrp
->IoStatus
.Information
= 0;
3438 DebugPrint((2, "CdRomDeviceControlCompletion: [%lx] completing CHECK_VERIFY buddy irp %lx\n", realIrp
, Irp
));
3441 case IOCTL_CDROM_GET_LAST_SESSION
:
3442 case IOCTL_CDROM_READ_TOC
: {
3444 PCDROM_TOC toc
= srb
->DataBuffer
;
3447 // Copy the device extension's geometry info into the user buffer.
3450 RtlMoveMemory(realIrp
->AssociatedIrp
.SystemBuffer
,
3452 srb
->DataTransferLength
);
3455 // update information field.
3458 realIrp
->IoStatus
.Information
= srb
->DataTransferLength
;
3462 case IOCTL_CDROM_PLAY_AUDIO_MSF
:
3464 PLAY_ACTIVE(deviceExtension
) = TRUE
;
3468 case IOCTL_CDROM_READ_Q_CHANNEL
: {
3470 PSUB_Q_CHANNEL_DATA userChannelData
= realIrp
->AssociatedIrp
.SystemBuffer
;
3472 PCDROM_SUB_Q_DATA_FORMAT inputBuffer
= realIrp
->AssociatedIrp
.SystemBuffer
;
3474 PSUB_Q_CHANNEL_DATA subQPtr
= srb
->DataBuffer
;
3477 switch( inputBuffer
->Format
) {
3479 case IOCTL_CDROM_CURRENT_POSITION
:
3480 DebugPrint((2,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr
->CurrentPosition
.Header
.AudioStatus
));
3481 DebugPrint((2,"CdRomDeviceControlCompletion: ADR = 0x%x\n", subQPtr
->CurrentPosition
.ADR
));
3482 DebugPrint((2,"CdRomDeviceControlCompletion: Control = 0x%x\n", subQPtr
->CurrentPosition
.Control
));
3483 DebugPrint((2,"CdRomDeviceControlCompletion: Track = %u\n", subQPtr
->CurrentPosition
.TrackNumber
));
3484 DebugPrint((2,"CdRomDeviceControlCompletion: Index = %u\n", subQPtr
->CurrentPosition
.IndexNumber
));
3485 DebugPrint((2,"CdRomDeviceControlCompletion: Absolute Address = %x\n", *((PULONG
)subQPtr
->CurrentPosition
.AbsoluteAddress
) ));
3486 DebugPrint((2,"CdRomDeviceControlCompletion: Relative Address = %x\n", *((PULONG
)subQPtr
->CurrentPosition
.TrackRelativeAddress
) ));
3489 case IOCTL_CDROM_MEDIA_CATALOG
:
3490 DebugPrint((2,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr
->MediaCatalog
.Header
.AudioStatus
));
3491 DebugPrint((2,"CdRomDeviceControlCompletion: Mcval is %u\n", subQPtr
->MediaCatalog
.Mcval
));
3494 case IOCTL_CDROM_TRACK_ISRC
:
3495 DebugPrint((2,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr
->TrackIsrc
.Header
.AudioStatus
));
3496 DebugPrint((2,"CdRomDeviceControlCompletion: Tcval is %u\n", subQPtr
->TrackIsrc
.Tcval
));
3503 // Update the play active status.
3506 if (subQPtr
->CurrentPosition
.Header
.AudioStatus
== AUDIO_STATUS_IN_PROGRESS
) {
3508 PLAY_ACTIVE(deviceExtension
) = TRUE
;
3512 PLAY_ACTIVE(deviceExtension
) = FALSE
;
3517 // Check if output buffer is large enough to contain
3521 if (realIrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
3522 srb
->DataTransferLength
) {
3524 srb
->DataTransferLength
=
3525 realIrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
3529 // Copy our buffer into users.
3532 RtlMoveMemory(userChannelData
,
3534 srb
->DataTransferLength
);
3536 realIrp
->IoStatus
.Information
= srb
->DataTransferLength
;
3540 case IOCTL_CDROM_PAUSE_AUDIO
:
3542 PLAY_ACTIVE(deviceExtension
) = FALSE
;
3543 realIrp
->IoStatus
.Information
= 0;
3546 case IOCTL_CDROM_RESUME_AUDIO
:
3548 realIrp
->IoStatus
.Information
= 0;
3551 case IOCTL_CDROM_SEEK_AUDIO_MSF
:
3553 realIrp
->IoStatus
.Information
= 0;
3556 case IOCTL_CDROM_STOP_AUDIO
:
3558 PLAY_ACTIVE(deviceExtension
) = FALSE
;
3560 realIrp
->IoStatus
.Information
= 0;
3563 case IOCTL_CDROM_GET_CONTROL
: {
3565 PCDROM_AUDIO_CONTROL audioControl
= srb
->DataBuffer
;
3566 PAUDIO_OUTPUT audioOutput
;
3567 ULONG bytesTransferred
;
3569 audioOutput
= ScsiClassFindModePage((PCHAR
)audioControl
,
3570 srb
->DataTransferLength
,
3571 CDROM_AUDIO_CONTROL_PAGE
,
3574 // Verify the page is as big as expected.
3577 bytesTransferred
= (PCHAR
) audioOutput
- (PCHAR
) audioControl
+
3578 sizeof(AUDIO_OUTPUT
);
3580 if (audioOutput
!= NULL
&&
3581 srb
->DataTransferLength
>= bytesTransferred
) {
3583 audioControl
->LbaFormat
= audioOutput
->LbaFormat
;
3585 audioControl
->LogicalBlocksPerSecond
=
3586 (audioOutput
->LogicalBlocksPerSecond
[0] << (UCHAR
)8) |
3587 audioOutput
->LogicalBlocksPerSecond
[1];
3589 realIrp
->IoStatus
.Information
= sizeof(CDROM_AUDIO_CONTROL
);
3592 realIrp
->IoStatus
.Information
= 0;
3593 status
= STATUS_INVALID_DEVICE_REQUEST
;
3598 case IOCTL_CDROM_GET_VOLUME
: {
3600 PAUDIO_OUTPUT audioOutput
;
3601 PVOLUME_CONTROL volumeControl
= srb
->DataBuffer
;
3602 ULONG i
,bytesTransferred
;
3604 audioOutput
= ScsiClassFindModePage((PCHAR
)volumeControl
,
3605 srb
->DataTransferLength
,
3606 CDROM_AUDIO_CONTROL_PAGE
,
3610 // Verify the page is as big as expected.
3613 bytesTransferred
= (PCHAR
) audioOutput
- (PCHAR
) volumeControl
+
3614 sizeof(AUDIO_OUTPUT
);
3616 if (audioOutput
!= NULL
&&
3617 srb
->DataTransferLength
>= bytesTransferred
) {
3619 for (i
=0; i
<4; i
++) {
3620 volumeControl
->PortVolume
[i
] =
3621 audioOutput
->PortOutput
[i
].Volume
;
3625 // Set bytes transferred in IRP.
3628 realIrp
->IoStatus
.Information
= sizeof(VOLUME_CONTROL
);
3631 realIrp
->IoStatus
.Information
= 0;
3632 status
= STATUS_INVALID_DEVICE_REQUEST
;
3638 case IOCTL_CDROM_SET_VOLUME
:
3640 realIrp
->IoStatus
.Information
= sizeof(VOLUME_CONTROL
);
3646 realIrp
->IoStatus
.Information
= 0;
3647 status
= STATUS_INVALID_DEVICE_REQUEST
;
3653 // Deallocate srb and sense buffer.
3657 if (srb
->DataBuffer
) {
3658 ExFreePool(srb
->DataBuffer
);
3660 if (srb
->SenseInfoBuffer
) {
3661 ExFreePool(srb
->SenseInfoBuffer
);
3666 if (realIrp
->PendingReturned
) {
3667 IoMarkIrpPending(realIrp
);
3670 if (Irp
->MdlAddress
) {
3671 IoFreeMdl(Irp
->MdlAddress
);
3677 // Set status in completing IRP.
3680 realIrp
->IoStatus
.Status
= status
;
3683 // Set the hard error if necessary.
3686 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
3689 // Store DeviceObject for filesystem, and clear
3690 // in IoStatus.Information field.
3693 DebugPrint((1, "CdRomDeviceCompletion - Setting Hard Error on realIrp %lx\n",
3695 IoSetHardErrorOrVerifyDevice(realIrp
, DeviceObject
);
3696 realIrp
->IoStatus
.Information
= 0;
3699 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
3701 IoStartNextPacket(DeviceObject
, FALSE
);
3703 return STATUS_MORE_PROCESSING_REQUIRED
;
3708 CdRomSetVolumeIntermediateCompletion(
3709 IN PDEVICE_OBJECT DeviceObject
,
3714 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3715 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3716 PCDROM_DATA cdData
= (PCDROM_DATA
)(deviceExtension
+ 1);
3717 BOOLEAN use6Byte
= cdData
->XAFlags
& XA_USE_6_BYTE
;
3718 PIO_STACK_LOCATION realIrpStack
;
3719 PIO_STACK_LOCATION realIrpNextStack
;
3720 PSCSI_REQUEST_BLOCK srb
= Context
;
3721 PIRP realIrp
= NULL
;
3726 // Extract the 'real' irp from the irpstack.
3729 realIrp
= (PIRP
) irpStack
->Parameters
.Others
.Argument2
;
3730 realIrpStack
= IoGetCurrentIrpStackLocation(realIrp
);
3731 realIrpNextStack
= IoGetNextIrpStackLocation(realIrp
);
3734 // Check SRB status for success of completing request.
3737 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
3740 "CdRomSetVolumeIntermediateCompletion: Irp %lx, Srb %lx Real Irp\n",
3746 // Release the queue if it is frozen.
3749 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
3750 ScsiClassReleaseQueue(DeviceObject
);
3754 retry
= ScsiClassInterpretSenseInfo(DeviceObject
,
3756 irpStack
->MajorFunction
,
3757 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
,
3758 MAXIMUM_RETRIES
- ((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
),
3761 if (status
== STATUS_DATA_OVERRUN
) {
3762 status
= STATUS_SUCCESS
;
3767 // If the status is verified required and the this request
3768 // should bypass verify required then retry the request.
3771 if (realIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
3772 status
== STATUS_VERIFY_REQUIRED
) {
3774 status
= STATUS_IO_DEVICE_ERROR
;
3778 if (retry
&& (realIrpNextStack
->Parameters
.Others
.Argument1
= (PVOID
)((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
-1))) {
3780 if (((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
)) {
3786 DebugPrint((1, "Retry request %lx - Calling StartIo\n", Irp
));
3789 ExFreePool(srb
->SenseInfoBuffer
);
3790 ExFreePool(srb
->DataBuffer
);
3792 if (Irp
->MdlAddress
) {
3793 IoFreeMdl(Irp
->MdlAddress
);
3799 // Call StartIo directly since IoStartNextPacket hasn't been called,
3800 // the serialisation is still intact.
3802 ScsiCdRomStartIo(DeviceObject
, realIrp
);
3803 return STATUS_MORE_PROCESSING_REQUIRED
;
3808 // Exhausted retries. Fall through and complete the request with the appropriate status.
3815 // Set status for successful request.
3818 status
= STATUS_SUCCESS
;
3821 if (NT_SUCCESS(status
)) {
3823 PAUDIO_OUTPUT audioInput
= NULL
;
3824 PAUDIO_OUTPUT audioOutput
;
3825 PVOLUME_CONTROL volumeControl
= realIrp
->AssociatedIrp
.SystemBuffer
;
3826 ULONG i
,bytesTransferred
,headerLength
;
3830 audioInput
= ScsiClassFindModePage((PCHAR
)srb
->DataBuffer
,
3831 srb
->DataTransferLength
,
3832 CDROM_AUDIO_CONTROL_PAGE
,
3836 // Check to make sure the mode sense data is valid before we go on
3839 if(audioInput
== NULL
) {
3841 DebugPrint((1, "Mode Sense Page %d not found\n",
3842 CDROM_AUDIO_CONTROL_PAGE
));
3844 realIrp
->IoStatus
.Information
= 0;
3845 realIrp
->IoStatus
.Status
= STATUS_IO_DEVICE_ERROR
;
3846 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
3847 ExFreePool(srb
->SenseInfoBuffer
);
3849 IoFreeMdl(Irp
->MdlAddress
);
3851 return STATUS_MORE_PROCESSING_REQUIRED
;
3855 headerLength
= sizeof(MODE_PARAMETER_HEADER
);
3857 headerLength
= sizeof(MODE_PARAMETER_HEADER10
);
3860 bytesTransferred
= sizeof(AUDIO_OUTPUT
) + headerLength
;
3863 // Allocate a new buffer for the mode select.
3866 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, bytesTransferred
);
3869 realIrp
->IoStatus
.Information
= 0;
3870 realIrp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3871 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
3872 ExFreePool(srb
->SenseInfoBuffer
);
3874 IoFreeMdl(Irp
->MdlAddress
);
3876 return STATUS_MORE_PROCESSING_REQUIRED
;
3879 RtlZeroMemory(dataBuffer
, bytesTransferred
);
3882 // Rebuild the data buffer to include the user requested values.
3885 audioOutput
= (PAUDIO_OUTPUT
) ((PCHAR
) dataBuffer
+ headerLength
);
3887 for (i
=0; i
<4; i
++) {
3888 audioOutput
->PortOutput
[i
].Volume
=
3889 volumeControl
->PortVolume
[i
];
3890 audioOutput
->PortOutput
[i
].ChannelSelection
=
3891 audioInput
->PortOutput
[i
].ChannelSelection
;
3894 audioOutput
->CodePage
= CDROM_AUDIO_CONTROL_PAGE
;
3895 audioOutput
->ParameterLength
= sizeof(AUDIO_OUTPUT
) - 2;
3896 audioOutput
->Immediate
= MODE_SELECT_IMMEDIATE
;
3899 // Free the old data buffer, mdl.
3902 ExFreePool(srb
->DataBuffer
);
3903 IoFreeMdl(Irp
->MdlAddress
);
3909 cdb
= (PCDB
)srb
->Cdb
;
3910 RtlZeroMemory(cdb
, CDB12GENERIC_LENGTH
);
3912 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
3913 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
3914 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_OUT
);
3915 srb
->DataTransferLength
= bytesTransferred
;
3919 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
3920 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
) bytesTransferred
;
3921 cdb
->MODE_SELECT
.PFBit
= 1;
3925 cdb
->MODE_SELECT10
.OperationCode
= SCSIOP_MODE_SELECT10
;
3926 cdb
->MODE_SELECT10
.ParameterListLength
[0] = (UCHAR
) (bytesTransferred
>> 8);
3927 cdb
->MODE_SELECT10
.ParameterListLength
[1] = (UCHAR
) (bytesTransferred
& 0xFF);
3928 cdb
->MODE_SELECT10
.PFBit
= 1;
3929 srb
->CdbLength
= 10;
3936 Irp
->MdlAddress
= IoAllocateMdl(dataBuffer
,
3942 if (!Irp
->MdlAddress
) {
3943 realIrp
->IoStatus
.Information
= 0;
3944 realIrp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3945 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
3946 ExFreePool(srb
->SenseInfoBuffer
);
3948 ExFreePool(dataBuffer
);
3950 return STATUS_MORE_PROCESSING_REQUIRED
;
3954 MmBuildMdlForNonPagedPool(Irp
->MdlAddress
);
3955 srb
->DataBuffer
= dataBuffer
;
3957 irpStack
= IoGetNextIrpStackLocation(Irp
);
3958 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
3959 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
3960 irpStack
->Parameters
.Scsi
.Srb
= srb
;
3963 // reset the irp completion.
3966 IoSetCompletionRoutine(Irp
,
3967 CdRomDeviceControlCompletion
,
3973 // Call the port driver.
3976 IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
3978 return STATUS_MORE_PROCESSING_REQUIRED
;
3982 // Deallocate srb and sense buffer.
3986 if (srb
->DataBuffer
) {
3987 ExFreePool(srb
->DataBuffer
);
3989 if (srb
->SenseInfoBuffer
) {
3990 ExFreePool(srb
->SenseInfoBuffer
);
3995 if (Irp
->PendingReturned
) {
3996 IoMarkIrpPending(Irp
);
3999 if (realIrp
->PendingReturned
) {
4000 IoMarkIrpPending(realIrp
);
4003 if (Irp
->MdlAddress
) {
4004 IoFreeMdl(Irp
->MdlAddress
);
4010 // Set status in completing IRP.
4013 realIrp
->IoStatus
.Status
= status
;
4016 // Set the hard error if necessary.
4019 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
4022 // Store DeviceObject for filesystem, and clear
4023 // in IoStatus.Information field.
4026 IoSetHardErrorOrVerifyDevice(realIrp
, DeviceObject
);
4027 realIrp
->IoStatus
.Information
= 0;
4030 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
4032 IoStartNextPacket(DeviceObject
, FALSE
);
4034 return STATUS_MORE_PROCESSING_REQUIRED
;
4040 CdRomSwitchModeCompletion(
4041 IN PDEVICE_OBJECT DeviceObject
,
4046 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4047 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
4048 PCDROM_DATA cdData
= (PCDROM_DATA
)(deviceExtension
+ 1);
4049 PIO_STACK_LOCATION realIrpStack
;
4050 PIO_STACK_LOCATION realIrpNextStack
;
4051 PSCSI_REQUEST_BLOCK srb
= Context
;
4052 PIRP realIrp
= NULL
;
4057 // Extract the 'real' irp from the irpstack.
4060 realIrp
= (PIRP
) irpStack
->Parameters
.Others
.Argument2
;
4061 realIrpStack
= IoGetCurrentIrpStackLocation(realIrp
);
4062 realIrpNextStack
= IoGetNextIrpStackLocation(realIrp
);
4065 // Check SRB status for success of completing request.
4068 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
4071 "CdRomSetVolumeIntermediateCompletion: Irp %lx, Srb %lx Real Irp\n",
4077 // Release the queue if it is frozen.
4080 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
4081 ScsiClassReleaseQueue(DeviceObject
);
4085 retry
= ScsiClassInterpretSenseInfo(DeviceObject
,
4087 irpStack
->MajorFunction
,
4088 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
,
4089 MAXIMUM_RETRIES
- ((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
),
4093 // If the status is verified required and the this request
4094 // should bypass verify required then retry the request.
4097 if (realIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
4098 status
== STATUS_VERIFY_REQUIRED
) {
4100 status
= STATUS_IO_DEVICE_ERROR
;
4104 if (retry
&& (realIrpNextStack
->Parameters
.Others
.Argument1
= (PVOID
)((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
-1))) {
4106 if (((ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
)) {
4112 DebugPrint((1, "Retry request %lx - Calling StartIo\n", Irp
));
4115 ExFreePool(srb
->SenseInfoBuffer
);
4116 ExFreePool(srb
->DataBuffer
);
4118 if (Irp
->MdlAddress
) {
4119 IoFreeMdl(Irp
->MdlAddress
);
4125 // Call StartIo directly since IoStartNextPacket hasn't been called,
4126 // the serialisation is still intact.
4129 ScsiCdRomStartIo(DeviceObject
, realIrp
);
4130 return STATUS_MORE_PROCESSING_REQUIRED
;
4135 // Exhausted retries. Fall through and complete the request with the appropriate status.
4141 // Set status for successful request.
4144 status
= STATUS_SUCCESS
;
4147 if (NT_SUCCESS(status
)) {
4149 ULONG sectorSize
, startingSector
, transferByteCount
;
4153 // Update device ext. to show which mode we are currently using.
4156 sectorSize
= cdData
->u1
.BlockDescriptor
.BlockLength
[0] << 16;
4157 sectorSize
|= (cdData
->u1
.BlockDescriptor
.BlockLength
[1] << 8);
4158 sectorSize
|= (cdData
->u1
.BlockDescriptor
.BlockLength
[2]);
4160 cdData
->RawAccess
= (sectorSize
== RAW_SECTOR_SIZE
) ? TRUE
: FALSE
;
4163 // Free the old data buffer, mdl.
4166 ExFreePool(srb
->DataBuffer
);
4167 IoFreeMdl(Irp
->MdlAddress
);
4174 cdb
= (PCDB
)srb
->Cdb
;
4175 RtlZeroMemory(cdb
, CDB12GENERIC_LENGTH
);
4178 if (cdData
->RawAccess
) {
4180 PRAW_READ_INFO rawReadInfo
=
4181 (PRAW_READ_INFO
)realIrpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
4183 ULONG maximumTransferLength
;
4184 ULONG transferPages
;
4187 // Calculate starting offset.
4190 startingSector
= (ULONG
)(rawReadInfo
->DiskOffset
.QuadPart
>> deviceExtension
->SectorShift
);
4191 transferByteCount
= rawReadInfo
->SectorCount
* RAW_SECTOR_SIZE
;
4192 maximumTransferLength
= deviceExtension
->PortCapabilities
->MaximumTransferLength
;
4193 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(realIrp
->MdlAddress
),
4197 // Determine if request is within limits imposed by miniport.
4198 // If the request is larger than the miniport's capabilities, split it.
4201 if (transferByteCount
> maximumTransferLength
||
4202 transferPages
> deviceExtension
->PortCapabilities
->MaximumPhysicalPages
) {
4204 realIrp
->IoStatus
.Information
= 0;
4205 realIrp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
4206 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
4208 ExFreePool(srb
->SenseInfoBuffer
);
4211 IoStartNextPacket(DeviceObject
, FALSE
);
4213 return STATUS_MORE_PROCESSING_REQUIRED
;
4216 srb
->OriginalRequest
= realIrp
;
4217 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
4218 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
4219 srb
->DataTransferLength
= transferByteCount
;
4220 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4221 srb
->CdbLength
= 10;
4222 srb
->DataBuffer
= MmGetMdlVirtualAddress(realIrp
->MdlAddress
);
4224 if (rawReadInfo
->TrackMode
== CDDA
) {
4225 if (cdData
->XAFlags
& PLEXTOR_CDDA
) {
4227 srb
->CdbLength
= 12;
4229 cdb
->PLXTR_READ_CDDA
.LogicalUnitNumber
= deviceExtension
->Lun
;
4230 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
4231 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
4232 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
4233 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
4235 cdb
->PLXTR_READ_CDDA
.TransferBlockByte3
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
4236 cdb
->PLXTR_READ_CDDA
.TransferBlockByte2
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
4237 cdb
->PLXTR_READ_CDDA
.TransferBlockByte1
= 0;
4238 cdb
->PLXTR_READ_CDDA
.TransferBlockByte0
= 0;
4240 cdb
->PLXTR_READ_CDDA
.SubCode
= 0;
4241 cdb
->PLXTR_READ_CDDA
.OperationCode
= 0xD8;
4243 } else if (cdData
->XAFlags
& NEC_CDDA
) {
4245 cdb
->NEC_READ_CDDA
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
4246 cdb
->NEC_READ_CDDA
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
4247 cdb
->NEC_READ_CDDA
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
4248 cdb
->NEC_READ_CDDA
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
4250 cdb
->NEC_READ_CDDA
.TransferBlockByte1
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
4251 cdb
->NEC_READ_CDDA
.TransferBlockByte0
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
4253 cdb
->NEC_READ_CDDA
.OperationCode
= 0xD4;
4256 cdb
->CDB10
.LogicalUnitNumber
= deviceExtension
->Lun
;
4258 cdb
->CDB10
.TransferBlocksMsb
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
4259 cdb
->CDB10
.TransferBlocksLsb
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
4261 cdb
->CDB10
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
4262 cdb
->CDB10
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
4263 cdb
->CDB10
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
4264 cdb
->CDB10
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
4266 cdb
->CDB10
.OperationCode
= SCSIOP_READ
;
4269 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
4272 irpStack
= IoGetNextIrpStackLocation(realIrp
);
4273 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
4274 irpStack
->Parameters
.Scsi
.Srb
= srb
;
4276 if (!(irpStack
->Parameters
.Others
.Argument1
)) {
4279 // Only jam this in if it doesn't exist. The completion routines can
4280 // call StartIo directly in the case of retries and resetting it will
4281 // cause infinite loops.
4284 irpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
4288 // Set up IoCompletion routine address.
4291 IoSetCompletionRoutine(realIrp
,
4299 ULONG maximumTransferLength
= deviceExtension
->PortCapabilities
->MaximumTransferLength
;
4300 ULONG transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(realIrp
->MdlAddress
),
4301 realIrpStack
->Parameters
.Read
.Length
);
4303 // Back to cooked sectors. Build and send a normal read.
4304 // The real work for setting offsets and checking for splitrequests was
4308 if ((realIrpStack
->Parameters
.Read
.Length
> maximumTransferLength
) ||
4309 (transferPages
> deviceExtension
->PortCapabilities
->MaximumPhysicalPages
)) {
4312 // Request needs to be split. Completion of each portion of the request will
4313 // fire off the next portion. The final request will signal Io to send a new request.
4316 ScsiClassSplitRequest(DeviceObject
, realIrp
, maximumTransferLength
);
4317 return STATUS_MORE_PROCESSING_REQUIRED
;
4322 // Build SRB and CDB for this IRP.
4325 ScsiClassBuildRequest(DeviceObject
, realIrp
);
4331 // Call the port driver.
4334 IoCallDriver(deviceExtension
->PortDeviceObject
, realIrp
);
4336 return STATUS_MORE_PROCESSING_REQUIRED
;
4340 // Update device Extension flags to indicate that XA isn't supported.
4343 cdData
->XAFlags
|= XA_NOT_SUPPORTED
;
4346 // Deallocate srb and sense buffer.
4350 if (srb
->DataBuffer
) {
4351 ExFreePool(srb
->DataBuffer
);
4353 if (srb
->SenseInfoBuffer
) {
4354 ExFreePool(srb
->SenseInfoBuffer
);
4359 if (Irp
->PendingReturned
) {
4360 IoMarkIrpPending(Irp
);
4363 if (realIrp
->PendingReturned
) {
4364 IoMarkIrpPending(realIrp
);
4367 if (Irp
->MdlAddress
) {
4368 IoFreeMdl(Irp
->MdlAddress
);
4374 // Set status in completing IRP.
4377 realIrp
->IoStatus
.Status
= status
;
4380 // Set the hard error if necessary.
4383 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
4386 // Store DeviceObject for filesystem, and clear
4387 // in IoStatus.Information field.
4390 IoSetHardErrorOrVerifyDevice(realIrp
, DeviceObject
);
4391 realIrp
->IoStatus
.Information
= 0;
4394 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
4396 IoStartNextPacket(DeviceObject
, FALSE
);
4398 return STATUS_MORE_PROCESSING_REQUIRED
;
4404 IN PDEVICE_OBJECT DeviceObject
,
4411 Routine Description:
4413 This routine executes when the port driver has completed a request.
4414 It looks at the SRB status in the completing SRB and if not success
4415 it checks for valid request sense buffer information. If valid, the
4416 info is used to update status with more precise message of type of
4417 error. This routine deallocates the SRB.
4421 DeviceObject - Supplies the device object which represents the logical
4424 Irp - Supplies the Irp which has completed.
4426 Context - Supplies a pointer to the SRB.
4435 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
4436 PIO_STACK_LOCATION irpNextStack
= IoGetNextIrpStackLocation(Irp
);
4437 PSCSI_REQUEST_BLOCK srb
= Context
;
4442 // Check SRB status for success of completing request.
4445 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
4447 DebugPrint((2,"ScsiClassIoComplete: IRP %lx, SRB %lx\n", Irp
, srb
));
4450 // Release the queue if it is frozen.
4453 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
4454 ScsiClassReleaseQueue(DeviceObject
);
4457 retry
= ScsiClassInterpretSenseInfo(
4460 irpStack
->MajorFunction
,
4461 irpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
? irpStack
->Parameters
.DeviceIoControl
.IoControlCode
: 0,
4462 MAXIMUM_RETRIES
- ((ULONG_PTR
)irpNextStack
->Parameters
.Others
.Argument1
),
4466 // If the status is verified required and the this request
4467 // should bypass verify required then retry the request.
4470 if (irpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
4471 status
== STATUS_VERIFY_REQUIRED
) {
4473 status
= STATUS_IO_DEVICE_ERROR
;
4477 if (retry
&& (irpNextStack
->Parameters
.Others
.Argument1
= (PVOID
)((ULONG_PTR
)irpNextStack
->Parameters
.Others
.Argument1
-1))) {
4479 if (((ULONG_PTR
)irpNextStack
->Parameters
.Others
.Argument1
)) {
4485 DebugPrint((1, "CdRomXACompletion: Retry request %lx - Calling StartIo\n", Irp
));
4488 ExFreePool(srb
->SenseInfoBuffer
);
4489 ExFreePool(srb
->DataBuffer
);
4493 // Call StartIo directly since IoStartNextPacket hasn't been called,
4494 // the serialisation is still intact.
4497 ScsiCdRomStartIo(DeviceObject
, Irp
);
4498 return STATUS_MORE_PROCESSING_REQUIRED
;
4503 // Exhausted retries. Fall through and complete the request with the appropriate status.
4509 // Set status for successful request.
4512 status
= STATUS_SUCCESS
;
4514 } // end if (SRB_STATUS(srb->SrbStatus) ...
4517 // Return SRB to nonpaged pool.
4523 // Set status in completing IRP.
4526 Irp
->IoStatus
.Status
= status
;
4529 // Set the hard error if necessary.
4532 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
4535 // Store DeviceObject for filesystem, and clear
4536 // in IoStatus.Information field.
4539 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
4540 Irp
->IoStatus
.Information
= 0;
4544 // If pending has be returned for this irp then mark the current stack as
4548 if (Irp
->PendingReturned
) {
4549 IoMarkIrpPending(Irp
);
4552 //IoCompleteRequest(Irp, IO_DISK_INCREMENT);
4553 IoStartNextPacket(DeviceObject
, FALSE
);
4561 IN PDEVICE_OBJECT DeviceObject
,
4567 Routine Description:
4569 This is the NT device control handler for CDROMs.
4573 DeviceObject - for this CDROM
4575 Irp - IO Request packet
4584 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
4585 PIO_STACK_LOCATION nextStack
;
4586 PKEVENT deviceControlEvent
;
4587 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4588 PCDROM_DATA cdData
= (PCDROM_DATA
)(deviceExtension
+1);
4589 SCSI_REQUEST_BLOCK srb
;
4600 // Zero the SRB on stack.
4603 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
4605 Irp
->IoStatus
.Information
= 0;
4608 // if this is a class driver ioctl then we need to change the base code
4609 // to IOCTL_CDROM_BASE so that the switch statement can handle it.
4611 // WARNING - currently the scsi class ioctl function codes are between
4612 // 0x200 & 0x300. this routine depends on that fact
4615 ioctlCode
= irpStack
->Parameters
.DeviceIoControl
.IoControlCode
;
4616 baseCode
= ioctlCode
>> 16;
4617 functionCode
= (ioctlCode
& (~0xffffc003)) >> 2;
4619 DebugPrint((1, "CdRomDeviceControl: Ioctl Code = %#08lx, Base Code = %#lx,"
4620 " Function Code = %#lx\n",
4626 if((functionCode
>= 0x200) && (functionCode
<= 0x300)) {
4628 ioctlCode
= (ioctlCode
& 0x0000ffff) | CTL_CODE(IOCTL_CDROM_BASE
, 0, 0, 0);
4630 DebugPrint((1, "CdRomDeviceControl: Class Code - new ioctl code is %#08lx\n",
4633 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= ioctlCode
;
4637 switch (ioctlCode
) {
4639 case IOCTL_CDROM_RAW_READ
: {
4641 LARGE_INTEGER startingOffset
;
4642 ULONG transferBytes
;
4643 PRAW_READ_INFO rawReadInfo
= (PRAW_READ_INFO
)irpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
4644 PUCHAR userData
= (PUCHAR
)Irp
->AssociatedIrp
.SystemBuffer
;
4647 // Ensure that XA reads are supported.
4650 if (cdData
->XAFlags
& XA_NOT_SUPPORTED
) {
4653 "CdRomDeviceControl: XA Reads not supported. Flags (%x)\n",
4656 status
= STATUS_INVALID_DEVICE_REQUEST
;
4661 // Check that ending sector is on disc and buffers are there and of
4665 if (rawReadInfo
== NULL
) {
4668 // Called from user space. Validate the buffers.
4671 rawReadInfo
= (PRAW_READ_INFO
)userData
;
4672 irpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
= (PVOID
)userData
;
4674 if (rawReadInfo
== NULL
) {
4676 DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (No extent info\n"));
4678 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
4680 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4681 return STATUS_INVALID_PARAMETER
;
4684 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
!= sizeof(RAW_READ_INFO
)) {
4686 DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (Invalid info buffer\n"));
4688 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
4690 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4691 return STATUS_INVALID_PARAMETER
;
4695 startingOffset
.QuadPart
= rawReadInfo
->DiskOffset
.QuadPart
;
4696 transferBytes
= rawReadInfo
->SectorCount
* RAW_SECTOR_SIZE
;
4698 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< transferBytes
) {
4700 DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (Bad buffer size)\n"));
4703 // Fail request with status of invalid parameters.
4706 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
4708 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4709 return STATUS_INVALID_PARAMETER
;
4712 if ((startingOffset
.QuadPart
+ transferBytes
) > deviceExtension
->PartitionLength
.QuadPart
) {
4714 DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (Request Out of Bounds)\n"));
4717 // Fail request with status of invalid parameters.
4720 status
= STATUS_INVALID_PARAMETER
;
4724 IoMarkIrpPending(Irp
);
4725 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4727 return STATUS_PENDING
;
4730 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
4731 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
: {
4733 DebugPrint((2,"CdRomDeviceControl: Get drive geometry\n"));
4735 if ( irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
4736 sizeof( DISK_GEOMETRY
) ) {
4738 status
= STATUS_INFO_LENGTH_MISMATCH
;
4742 IoMarkIrpPending(Irp
);
4743 IoStartPacket(DeviceObject
,Irp
, NULL
,NULL
);
4745 return STATUS_PENDING
;
4748 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX
:
4749 case IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX
: {
4751 DebugPrint((2,"CdRomDeviceControl: Get drive geometry ex\n"));
4753 if ( irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
4754 sizeof( DISK_GEOMETRY_EX
) ) {
4756 status
= STATUS_INFO_LENGTH_MISMATCH
;
4760 IoMarkIrpPending(Irp
);
4761 IoStartPacket(DeviceObject
,Irp
, NULL
,NULL
);
4763 return STATUS_PENDING
;
4766 case IOCTL_DISK_GET_LENGTH_INFO
: {
4768 DebugPrint((2,"CdRomDeviceControl: Get length info\n"));
4770 if ( irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
4771 sizeof( GET_LENGTH_INFORMATION
) ) {
4773 status
= STATUS_INFO_LENGTH_MISMATCH
;
4777 IoMarkIrpPending(Irp
);
4778 IoStartPacket(DeviceObject
,Irp
, NULL
,NULL
);
4780 return STATUS_PENDING
;
4783 case IOCTL_CDROM_GET_LAST_SESSION
:
4784 case IOCTL_CDROM_READ_TOC
: {
4787 // If the cd is playing music then reject this request.
4790 if (CdRomIsPlayActive(DeviceObject
)) {
4791 Irp
->IoStatus
.Status
= STATUS_DEVICE_BUSY
;
4792 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4793 return STATUS_DEVICE_BUSY
;
4796 IoMarkIrpPending(Irp
);
4797 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4799 return STATUS_PENDING
;
4802 case IOCTL_CDROM_PLAY_AUDIO_MSF
: {
4808 DebugPrint((2,"CdRomDeviceControl: Play audio MSF\n"));
4810 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
4811 sizeof(CDROM_PLAY_AUDIO_MSF
)) {
4814 // Indicate unsuccessful status.
4817 status
= STATUS_BUFFER_TOO_SMALL
;
4821 IoMarkIrpPending(Irp
);
4822 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4824 return STATUS_PENDING
;
4827 case IOCTL_CDROM_SEEK_AUDIO_MSF
: {
4834 DebugPrint((2,"CdRomDeviceControl: Seek audio MSF\n"));
4836 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
4837 sizeof(CDROM_SEEK_AUDIO_MSF
)) {
4840 // Indicate unsuccessful status.
4843 status
= STATUS_BUFFER_TOO_SMALL
;
4846 IoMarkIrpPending(Irp
);
4847 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4849 return STATUS_PENDING
;
4854 case IOCTL_CDROM_PAUSE_AUDIO
: {
4860 DebugPrint((2, "CdRomDeviceControl: Pause audio\n"));
4862 IoMarkIrpPending(Irp
);
4863 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4865 return STATUS_PENDING
;
4870 case IOCTL_CDROM_RESUME_AUDIO
: {
4876 DebugPrint((2, "CdRomDeviceControl: Resume audio\n"));
4878 IoMarkIrpPending(Irp
);
4879 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4881 return STATUS_PENDING
;
4884 case IOCTL_CDROM_READ_Q_CHANNEL
: {
4886 if(irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
4887 sizeof(CDROM_SUB_Q_DATA_FORMAT
)) {
4889 status
= STATUS_BUFFER_TOO_SMALL
;
4890 Irp
->IoStatus
.Information
= 0;
4894 IoMarkIrpPending(Irp
);
4895 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4897 return STATUS_PENDING
;
4900 case IOCTL_CDROM_GET_CONTROL
: {
4902 DebugPrint((2, "CdRomDeviceControl: Get audio control\n"));
4905 // Verify user buffer is large enough for the data.
4908 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
4909 sizeof(CDROM_AUDIO_CONTROL
)) {
4912 // Indicate unsuccessful status and no data transferred.
4915 status
= STATUS_BUFFER_TOO_SMALL
;
4916 Irp
->IoStatus
.Information
= 0;
4921 IoMarkIrpPending(Irp
);
4922 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4924 return STATUS_PENDING
;
4928 case IOCTL_CDROM_GET_VOLUME
: {
4930 DebugPrint((2, "CdRomDeviceControl: Get volume control\n"));
4933 // Verify user buffer is large enough for data.
4936 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
4937 sizeof(VOLUME_CONTROL
)) {
4940 // Indicate unsuccessful status and no data transferred.
4943 status
= STATUS_BUFFER_TOO_SMALL
;
4944 Irp
->IoStatus
.Information
= 0;
4948 IoMarkIrpPending(Irp
);
4949 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4951 return STATUS_PENDING
;
4955 case IOCTL_CDROM_SET_VOLUME
: {
4957 DebugPrint((2, "CdRomDeviceControl: Set volume control\n"));
4959 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
4960 sizeof(VOLUME_CONTROL
)) {
4963 // Indicate unsuccessful status.
4966 status
= STATUS_BUFFER_TOO_SMALL
;
4970 IoMarkIrpPending(Irp
);
4971 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4973 return STATUS_PENDING
;
4977 case IOCTL_CDROM_STOP_AUDIO
: {
4983 DebugPrint((2, "CdRomDeviceControl: Stop audio\n"));
4985 IoMarkIrpPending(Irp
);
4986 IoStartPacket(DeviceObject
,Irp
, NULL
,NULL
);
4988 return STATUS_PENDING
;
4991 case IOCTL_CDROM_CHECK_VERIFY
: {
4992 DebugPrint((1, "CdRomDeviceControl: [%lx] Check Verify\n", Irp
));
4993 IoMarkIrpPending(Irp
);
4995 if((irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
) &&
4996 (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))) {
4998 DebugPrint((1, "CdRomDeviceControl: Check Verify: media count "
4999 "buffer too small\n"));
5001 status
= STATUS_BUFFER_TOO_SMALL
;
5005 IoStartPacket(DeviceObject
,Irp
, NULL
,NULL
);
5007 return STATUS_PENDING
;
5013 // allocate an event and stuff it into our stack location.
5016 deviceControlEvent
= ExAllocatePool(NonPagedPool
, sizeof(KEVENT
));
5018 if(!deviceControlEvent
) {
5020 status
= STATUS_INSUFFICIENT_RESOURCES
;
5024 PIO_STACK_LOCATION currentStack
;
5026 KeInitializeEvent(deviceControlEvent
, NotificationEvent
, FALSE
);
5028 currentStack
= IoGetCurrentIrpStackLocation(Irp
);
5029 nextStack
= IoGetNextIrpStackLocation(Irp
);
5032 // Copy the stack down a notch
5035 *nextStack
= *currentStack
;
5037 IoSetCompletionRoutine(
5039 CdRomClassIoctlCompletion
,
5046 IoSetNextIrpStackLocation(Irp
);
5048 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
5049 Irp
->IoStatus
.Information
= 0;
5052 // Override volume verifies on this stack location so that we
5053 // will be forced through the synchronization. Once this location
5054 // goes away we get the old value back
5057 nextStack
->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
5059 IoMarkIrpPending(Irp
);
5061 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
5064 // Wait for CdRomClassIoctlCompletion to set the event. This
5065 // ensures serialization remains intact for these unhandled device
5069 KeWaitForSingleObject(
5076 ExFreePool(deviceControlEvent
);
5078 DebugPrint((2, "CdRomDeviceControl: irp %#08lx synchronized\n", Irp
));
5081 // If an error occured then propagate that back up - we are no longer
5082 // guaranteed synchronization and the upper layers will have to
5085 // If no error occured, call down to the class driver directly
5086 // then start up the next request.
5089 if(Irp
->IoStatus
.Status
== STATUS_SUCCESS
) {
5091 status
= ScsiClassDeviceControl(DeviceObject
, Irp
);
5093 KeRaiseIrql(DISPATCH_LEVEL
, &irql
);
5095 IoStartNextPacket(DeviceObject
, FALSE
);
5106 if (status
== STATUS_VERIFY_REQUIRED
) {
5109 // If the status is verified required and this request
5110 // should bypass verify required then retry the request.
5113 if (irpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
) {
5115 status
= STATUS_IO_DEVICE_ERROR
;
5121 if (IoIsErrorUserInduced(status
)) {
5123 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
5128 // Update IRP with completion status.
5131 Irp
->IoStatus
.Status
= status
;
5134 // Complete the request.
5137 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
5138 DebugPrint((2, "CdRomDeviceControl: Status is %lx\n", status
));
5141 } // end ScsiCdRomDeviceControl()
5146 PDEVICE_OBJECT DeviceObject
,
5147 PINQUIRYDATA InquiryData
,
5148 PIO_SCSI_CAPABILITIES PortCapabilities
5153 Routine Description:
5155 This function checks to see if an SCSI logical unit requires an special
5156 initialization or error processing.
5160 DeviceObject - Supplies the device object to be tested.
5162 InquiryData - Supplies the inquiry data returned by the device of interest.
5164 PortCapabilities - Supplies the capabilities of the device object.
5173 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
5174 PCDROM_DATA cdData
= (PCDROM_DATA
)(deviceExtension
+1);
5177 // Look for a Hitachi CDR-1750. Read-ahead must be disabled in order
5178 // to get this cdrom drive to work on scsi adapters that use PIO.
5181 if ((strncmp((PCHAR
)InquiryData
->VendorId
, "HITACHI CDR-1750S", strlen("HITACHI CDR-1750S")) == 0 ||
5182 strncmp((PCHAR
)InquiryData
->VendorId
, "HITACHI CDR-3650/1650S", strlen("HITACHI CDR-3650/1650S")) == 0)
5183 && PortCapabilities
->AdapterUsesPio
) {
5185 DebugPrint((1, "CdRom ScanForSpecial: Found Hitachi CDR-1750S.\n"));
5188 // Setup an error handler to reinitialize the cd rom after it is reset.
5191 deviceExtension
->ClassError
= HitachProcessError
;
5193 } else if (( RtlCompareMemory( InquiryData
->VendorId
,"FUJITSU", 7 ) == 7 ) &&
5194 (( RtlCompareMemory( InquiryData
->ProductId
,"FMCD-101", 8 ) == 8 ) ||
5195 ( RtlCompareMemory( InquiryData
->ProductId
,"FMCD-102", 8 ) == 8 ))) {
5198 // When Read command is issued to FMCD-101 or FMCD-102 and there is a music
5199 // cd in it. It takes longer time than SCSI_CDROM_TIMEOUT before returning
5203 deviceExtension
->TimeOutValue
= 20;
5205 } else if (( RtlCompareMemory( InquiryData
->VendorId
,"TOSHIBA", 7) == 7) &&
5206 (( RtlCompareMemory( InquiryData
->ProductId
,"CD-ROM XM-34", 12) == 12))) {
5208 SCSI_REQUEST_BLOCK srb
;
5215 // Set the density code and the error handler.
5218 length
= (sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH
);
5220 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
5223 // Build the MODE SENSE CDB.
5227 cdb
= (PCDB
)srb
.Cdb
;
5230 // Set timeout value from device extension.
5233 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
5235 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
5236 cdb
->MODE_SENSE
.PageCode
= 0x1;
5237 cdb
->MODE_SENSE
.AllocationLength
= (UCHAR
)length
;
5239 buffer
= ExAllocatePool(NonPagedPoolCacheAligned
, (sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH
));
5244 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
5250 ((PERROR_RECOVERY_DATA
)buffer
)->BlockDescriptor
.DensityCode
= 0x83;
5251 ((PERROR_RECOVERY_DATA
)buffer
)->Header
.ModeDataLength
= 0x0;
5253 RtlCopyMemory(&cdData
->u1
.Header
, buffer
, sizeof(ERROR_RECOVERY_DATA
));
5255 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
5258 // Build the MODE SENSE CDB.
5262 cdb
= (PCDB
)srb
.Cdb
;
5265 // Set timeout value from device extension.
5268 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
5270 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
5271 cdb
->MODE_SELECT
.PFBit
= 1;
5272 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)length
;
5274 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
5280 if (!NT_SUCCESS(status
)) {
5282 "Cdrom.ScanForSpecial: Setting density code on Toshiba failed [%x]\n",
5286 deviceExtension
->ClassError
= ToshibaProcessError
;
5293 // Determine special CD-DA requirements.
5296 if (RtlCompareMemory( InquiryData
->VendorId
,"PLEXTOR",7) == 7) {
5297 cdData
->XAFlags
|= PLEXTOR_CDDA
;
5298 } else if (RtlCompareMemory ( InquiryData
->VendorId
,"NEC",3) == 3) {
5299 cdData
->XAFlags
|= NEC_CDDA
;
5308 PDEVICE_OBJECT DeviceObject
,
5309 PSCSI_REQUEST_BLOCK Srb
,
5315 Routine Description:
5317 This routine checks the type of error. If the error indicates CD-ROM the
5318 CD-ROM needs to be reinitialized then a Mode sense command is sent to the
5319 device. This command disables read-ahead for the device.
5323 DeviceObject - Supplies a pointer to the device object.
5325 Srb - Supplies a pointer to the failing Srb.
5338 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
5339 PSENSE_DATA senseBuffer
= Srb
->SenseInfoBuffer
;
5340 LARGE_INTEGER largeInt
;
5342 PIO_STACK_LOCATION irpStack
;
5344 PSCSI_REQUEST_BLOCK srb
;
5345 PCOMPLETION_CONTEXT context
;
5349 UNREFERENCED_PARAMETER(Status
);
5350 UNREFERENCED_PARAMETER(Retry
);
5352 largeInt
.QuadPart
= (LONGLONG
) 1;
5355 // Check the status. The initialization command only needs to be sent
5356 // if UNIT ATTENTION is returned.
5359 if (!(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
)) {
5362 // The drive does not require reinitialization.
5369 // Found a bad HITACHI cd-rom. These devices do not work with PIO
5370 // adapters when read-ahead is enabled. Read-ahead is disabled by
5371 // a mode select command. The mode select page code is zero and the
5372 // length is 6 bytes. All of the other bytes should be zero.
5376 if ((senseBuffer
->SenseKey
& 0xf) == SCSI_SENSE_UNIT_ATTENTION
) {
5378 DebugPrint((1, "HitachiProcessError: Reinitializing the CD-ROM.\n"));
5381 // Send the special mode select command to disable read-ahead
5382 // on the CD-ROM reader.
5385 alignment
= DeviceObject
->AlignmentRequirement
?
5386 DeviceObject
->AlignmentRequirement
: 1;
5388 context
= ExAllocatePool(
5390 sizeof(COMPLETION_CONTEXT
) + HITACHI_MODE_DATA_SIZE
+ alignment
5393 if (context
== NULL
) {
5396 // If there is not enough memory to fulfill this request,
5397 // simply return. A subsequent retry will fail and another
5398 // chance to start the unit.
5404 context
->DeviceObject
= DeviceObject
;
5405 srb
= &context
->Srb
;
5407 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
5410 // Write length to SRB.
5413 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
5416 // Set up SCSI bus address.
5419 srb
->PathId
= deviceExtension
->PathId
;
5420 srb
->TargetId
= deviceExtension
->TargetId
;
5421 srb
->Lun
= deviceExtension
->Lun
;
5423 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
5424 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
5427 // Set the transfer length.
5430 srb
->DataTransferLength
= HITACHI_MODE_DATA_SIZE
;
5431 srb
->SrbFlags
= SRB_FLAGS_DATA_OUT
| SRB_FLAGS_DISABLE_AUTOSENSE
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
5434 // The data buffer must be aligned.
5437 srb
->DataBuffer
= (PVOID
) (((ULONG_PTR
) (context
+ 1) + (alignment
- 1)) &
5442 // Build the HITACHI read-ahead mode select CDB.
5446 cdb
= (PCDB
)srb
->Cdb
;
5447 cdb
->MODE_SENSE
.LogicalUnitNumber
= srb
->Lun
;
5448 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SELECT
;
5449 cdb
->MODE_SENSE
.AllocationLength
= HITACHI_MODE_DATA_SIZE
;
5452 // Initialize the mode sense data.
5455 modePage
= srb
->DataBuffer
;
5457 RtlZeroMemory(modePage
, HITACHI_MODE_DATA_SIZE
);
5460 // Set the page length field to 6.
5466 // Build the asynchronous request to be sent to the port driver.
5469 irp
= IoBuildAsynchronousFsdRequest(IRP_MJ_WRITE
,
5472 srb
->DataTransferLength
,
5476 IoSetCompletionRoutine(irp
,
5477 (PIO_COMPLETION_ROUTINE
)ScsiClassAsynchronousCompletion
,
5483 irpStack
= IoGetNextIrpStackLocation(irp
);
5485 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
5487 srb
->OriginalRequest
= irp
;
5490 // Save SRB address in next stack for port driver.
5493 irpStack
->Parameters
.Scsi
.Srb
= (PVOID
)srb
;
5496 // Set up IRP Address.
5499 (VOID
)IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
5506 ToshibaProcessErrorCompletion(
5507 PDEVICE_OBJECT DeviceObject
,
5514 Routine Description:
5516 Completion routine for the ClassError routine to handle older Toshiba units
5517 that require setting the density code.
5521 DeviceObject - Supplies a pointer to the device object.
5523 Irp - Pointer to irp created to set the density code.
5525 Context - Supplies a pointer to the Mode Select Srb.
5530 STATUS_MORE_PROCESSING_REQUIRED
5536 PSCSI_REQUEST_BLOCK srb
= Context
;
5539 // Check for a frozen queue.
5542 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
5545 // Unfreeze the queue getting the device object from the context.
5548 ScsiClassReleaseQueue(DeviceObject
);
5552 // Free all of the allocations.
5555 ExFreePool(srb
->DataBuffer
);
5557 IoFreeMdl(Irp
->MdlAddress
);
5561 // Indicate the I/O system should stop processing the Irp completion.
5564 return STATUS_MORE_PROCESSING_REQUIRED
;
5569 ToshibaProcessError(
5570 PDEVICE_OBJECT DeviceObject
,
5571 PSCSI_REQUEST_BLOCK Srb
,
5578 Routine Description:
5580 This routine checks the type of error. If the error indicates a unit attention,
5581 the density code needs to be set via a Mode select command.
5585 DeviceObject - Supplies a pointer to the device object.
5587 Srb - Supplies a pointer to the failing Srb.
5600 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
5601 PCDROM_DATA cdData
= (PCDROM_DATA
)(deviceExtension
+1);
5602 PSENSE_DATA senseBuffer
= Srb
->SenseInfoBuffer
;
5603 PIO_STACK_LOCATION irpStack
;
5605 PSCSI_REQUEST_BLOCK srb
;
5611 if (!(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
)) {
5616 // The Toshiba's require the density code to be set on power up and media changes.
5619 if ((senseBuffer
->SenseKey
& 0xf) == SCSI_SENSE_UNIT_ATTENTION
) {
5622 irp
= IoAllocateIrp((CCHAR
)(deviceExtension
->DeviceObject
->StackSize
+1),
5629 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
5636 length
= sizeof(ERROR_RECOVERY_DATA
);
5637 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, length
);
5644 irp
->MdlAddress
= IoAllocateMdl(dataBuffer
,
5650 if (!irp
->MdlAddress
) {
5652 ExFreePool(dataBuffer
);
5661 MmBuildMdlForNonPagedPool(irp
->MdlAddress
);
5663 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
5665 srb
->DataBuffer
= dataBuffer
;
5666 cdb
= (PCDB
)srb
->Cdb
;
5672 IoSetNextIrpStackLocation(irp
);
5673 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
5674 irp
->IoStatus
.Information
= 0;
5676 irp
->UserBuffer
= NULL
;
5679 // Save the device object and irp in a private stack location.
5682 irpStack
= IoGetCurrentIrpStackLocation(irp
);
5683 irpStack
->DeviceObject
= deviceExtension
->DeviceObject
;
5686 // Construct the IRP stack for the lower level driver.
5689 irpStack
= IoGetNextIrpStackLocation(irp
);
5690 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
5691 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_OUT
;
5692 irpStack
->Parameters
.Scsi
.Srb
= srb
;
5694 IoSetCompletionRoutine(irp
,
5695 ToshibaProcessErrorCompletion
,
5701 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
5702 srb
->PathId
= deviceExtension
->PathId
;
5703 srb
->TargetId
= deviceExtension
->TargetId
;
5704 srb
->Lun
= deviceExtension
->Lun
;
5705 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
5706 srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
5707 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
5709 srb
->OriginalRequest
= irp
;
5710 srb
->SenseInfoBufferLength
= 0;
5713 // Set the transfer length.
5716 srb
->DataTransferLength
= length
;
5717 srb
->SrbFlags
= SRB_FLAGS_DATA_OUT
| SRB_FLAGS_DISABLE_AUTOSENSE
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
5721 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
5722 cdb
->MODE_SELECT
.PFBit
= 1;
5723 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)length
;
5726 // Copy the Mode page into the databuffer.
5729 RtlCopyMemory(srb
->DataBuffer
, &cdData
->u1
.Header
, length
);
5732 // Set the density code.
5735 ((PERROR_RECOVERY_DATA
)srb
->DataBuffer
)->BlockDescriptor
.DensityCode
= 0x83;
5737 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
5744 IN PDEVICE_OBJECT DeviceObject
5749 Routine Description:
5751 This routine determines if the cd is currently playing music.
5755 DeviceObject - Device object to test.
5759 TRUE if the device is playing music.
5763 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
5765 IO_STATUS_BLOCK ioStatus
;
5768 PSUB_Q_CURRENT_POSITION currentBuffer
;
5770 if (!PLAY_ACTIVE(deviceExtension
)) {
5774 currentBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, sizeof(SUB_Q_CURRENT_POSITION
));
5776 if (currentBuffer
== NULL
) {
5780 ((PCDROM_SUB_Q_DATA_FORMAT
) currentBuffer
)->Format
= IOCTL_CDROM_CURRENT_POSITION
;
5781 ((PCDROM_SUB_Q_DATA_FORMAT
) currentBuffer
)->Track
= 0;
5784 // Create notification event object to be used to signal the
5785 // request completion.
5788 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
5791 // Build the synchronous request to be sent to the port driver
5792 // to perform the request.
5795 irp
= IoBuildDeviceIoControlRequest(IOCTL_CDROM_READ_Q_CHANNEL
,
5796 deviceExtension
->DeviceObject
,
5798 sizeof(CDROM_SUB_Q_DATA_FORMAT
),
5800 sizeof(SUB_Q_CURRENT_POSITION
),
5806 ExFreePool(currentBuffer
);
5811 // Pass request to port driver and wait for request to complete.
5814 status
= IoCallDriver(deviceExtension
->DeviceObject
, irp
);
5816 if (status
== STATUS_PENDING
) {
5817 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
5818 status
= ioStatus
.Status
;
5821 if (!NT_SUCCESS(status
)) {
5822 ExFreePool(currentBuffer
);
5826 ExFreePool(currentBuffer
);
5828 return(PLAY_ACTIVE(deviceExtension
));
5832 IO_COMPLETION_ROUTINE CdRomMediaChangeCompletion
;
5835 CdRomMediaChangeCompletion(
5836 PDEVICE_OBJECT DeviceObject
,
5843 Routine Description:
5845 This routine handles the completion of the test unit ready irps
5846 used to determine if the media has changed. If the media has
5847 changed, this code signals the named event to wake up other
5848 system services that react to media change (aka AutoPlay).
5852 DeviceObject - the object for the completion
5853 Irp - the IRP being completed
5854 Context - the SRB from the IRP
5863 PSCSI_REQUEST_BLOCK srb
= (PSCSI_REQUEST_BLOCK
) Context
;
5864 PIO_STACK_LOCATION cdStack
= IoGetCurrentIrpStackLocation(Irp
);
5865 PIO_STACK_LOCATION irpNextStack
= IoGetNextIrpStackLocation(Irp
);
5866 PDEVICE_EXTENSION deviceExtension
;
5867 PDEVICE_EXTENSION physicalExtension
;
5868 PSENSE_DATA senseBuffer
;
5873 DeviceObject
= cdStack
->DeviceObject
;
5874 ASSERT(DeviceObject
);
5876 deviceExtension
= DeviceObject
->DeviceExtension
;
5877 physicalExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
5878 cddata
= (PCDROM_DATA
)(deviceExtension
+ 1);
5880 ASSERT(cddata
->MediaChangeIrp
== NULL
);
5883 // If the sense data field is valid, look for a media change.
5884 // otherwise this iteration of the polling will just assume nothing
5888 DebugPrint((3, "CdRomMediaChangeHandler: Completing Autorun Irp 0x%lx "
5890 Irp
, deviceExtension
->DeviceNumber
));
5892 if (srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) {
5893 if (srb
->SenseInfoBufferLength
>= FIELD_OFFSET(SENSE_DATA
, CommandSpecificInformation
)) {
5896 // See if this is a media change.
5899 senseBuffer
= srb
->SenseInfoBuffer
;
5900 if ((senseBuffer
->SenseKey
& 0x0f) == SCSI_SENSE_UNIT_ATTENTION
) {
5901 if (senseBuffer
->AdditionalSenseCode
== SCSI_ADSENSE_MEDIUM_CHANGED
) {
5903 DebugPrint((1, "CdRomMediaChangeCompletion: New media inserted "
5904 "into CdRom%d [irp = 0x%lx]\n",
5905 deviceExtension
->DeviceNumber
, Irp
));
5908 // Media change event occurred - signal the named event.
5911 KeSetEvent(deviceExtension
->MediaChangeEvent
,
5915 deviceExtension
->MediaChangeNoMedia
= FALSE
;
5919 if (DeviceObject
->Vpb
->Flags
& VPB_MOUNTED
) {
5922 // Must remember the media changed and force the
5923 // file system to verify on next access
5926 DeviceObject
->Flags
|= DO_VERIFY_VOLUME
;
5929 physicalExtension
->MediaChangeCount
++;
5931 } else if(((senseBuffer
->SenseKey
& 0x0f) == SCSI_SENSE_NOT_READY
)&&
5932 (senseBuffer
->AdditionalSenseCode
== SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
)&&
5933 (!deviceExtension
->MediaChangeNoMedia
)){
5936 // If there was no media in the device then signal the waiters if
5937 // we haven't already done so before.
5940 DebugPrint((1, "CdRomMediaChangeCompletion: No media in device"
5941 "CdRom%d [irp = 0x%lx]\n",
5942 deviceExtension
->DeviceNumber
, Irp
));
5944 KeSetEvent(deviceExtension
->MediaChangeEvent
,
5948 deviceExtension
->MediaChangeNoMedia
= TRUE
;
5952 } else if((srb
->SrbStatus
== SRB_STATUS_SUCCESS
)&&
5953 (deviceExtension
->MediaChangeNoMedia
)) {
5955 // We didn't have any media before and now the requests are succeeding
5956 // we probably missed the Media change somehow. Signal the change
5960 DebugPrint((1, "CdRomMediaChangeCompletion: Request completed normally"
5961 "for CdRom%d which was marked w/NoMedia [irp = 0x%lx]\n",
5962 deviceExtension
->DeviceNumber
, Irp
));
5964 KeSetEvent(deviceExtension
->MediaChangeEvent
,
5968 deviceExtension
->MediaChangeNoMedia
= FALSE
;
5972 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
5973 ScsiClassReleaseQueue(deviceExtension
->DeviceObject
);
5977 // Remember the IRP and SRB for use the next time.
5980 irpNextStack
->Parameters
.Scsi
.Srb
= srb
;
5981 cddata
->MediaChangeIrp
= Irp
;
5983 if (deviceExtension
->ClassError
) {
5989 // Throw away the status and retry values. Just give the error routine a chance
5990 // to do what it needs to.
5993 deviceExtension
->ClassError(DeviceObject
,
5999 IoStartNextPacket(DeviceObject
, FALSE
);
6001 return STATUS_MORE_PROCESSING_REQUIRED
;
6007 IN PDEVICE_OBJECT DeviceObject
,
6013 Routine Description:
6015 This routine handles the once per second timer provided by the
6016 Io subsystem. It is only used when the cdrom device itself is
6017 a candidate for autoplay support. It should never be called if
6018 the cdrom device is a changer device.
6022 DeviceObject - what to check.
6035 PLIST_ENTRY listEntry
;
6037 PIO_STACK_LOCATION irpStack
;
6038 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
6040 cddata
= (PCDROM_DATA
)(deviceExtension
+ 1);
6042 if (cddata
->MediaChange
) {
6043 if (cddata
->MediaChangeIrp
!= NULL
) {
6046 // Media change support is active and the IRP is waiting.
6047 // Decrement the timer.
6048 // There is no MP protection on the timer counter. This
6049 // code is the only code that will manipulate the timer
6050 // and only one instance of it should be running at any
6054 cddata
->MediaChangeCountDown
--;
6057 cddata
->MediaChangeIrpTimeInUse
= 0;
6058 cddata
->MediaChangeIrpLost
= FALSE
;
6061 if (!cddata
->MediaChangeCountDown
) {
6062 PSCSI_REQUEST_BLOCK srb
;
6063 PIO_STACK_LOCATION irpNextStack
;
6070 cddata
->MediaChangeCountDown
= MEDIA_CHANGE_DEFAULT_TIME
;
6073 // Prepare the IRP for the test unit ready
6076 irp
= cddata
->MediaChangeIrp
;
6077 cddata
->MediaChangeIrp
= NULL
;
6079 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
6080 irp
->IoStatus
.Information
= 0;
6082 irp
->UserBuffer
= NULL
;
6085 // If the irp is sent down when the volume needs to be
6086 // verified, CdRomUpdateGeometryCompletion won't complete
6087 // it since it's not associated with a thread. Marking
6088 // it to override the verify causes it always be sent
6089 // to the port driver
6092 irpStack
= IoGetCurrentIrpStackLocation(irp
);
6093 irpStack
->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
6095 irpNextStack
= IoGetNextIrpStackLocation(irp
);
6096 irpNextStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
6097 irpNextStack
->Parameters
.DeviceIoControl
.IoControlCode
=
6098 IOCTL_SCSI_EXECUTE_NONE
;
6101 // Prepare the SRB for execution.
6104 srb
= irpNextStack
->Parameters
.Scsi
.Srb
;
6105 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
6107 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
6108 srb
->PathId
= deviceExtension
->PathId
;
6109 srb
->TargetId
= deviceExtension
->TargetId
;
6110 srb
->Lun
= deviceExtension
->Lun
;
6111 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
6112 srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
|
6113 SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
6114 srb
->DataTransferLength
= 0;
6115 srb
->OriginalRequest
= irp
;
6117 RtlZeroMemory(srb
->SenseInfoBuffer
, SENSE_BUFFER_SIZE
);
6118 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
6120 cdb
= (PCDB
) &srb
->Cdb
[0];
6121 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_TEST_UNIT_READY
;
6122 cdb
->CDB6GENERIC
.LogicalUnitNumber
= srb
->Lun
;
6125 // Setup the IRP to perform a test unit ready.
6128 IoSetCompletionRoutine(irp
,
6129 CdRomMediaChangeCompletion
,
6136 // Issue the request.
6139 IoStartPacket(DeviceObject
, irp
, NULL
, NULL
);
6144 if(cddata
->MediaChangeIrpLost
== FALSE
) {
6145 if(cddata
->MediaChangeIrpTimeInUse
++ >
6146 MEDIA_CHANGE_TIMEOUT_TIME
) {
6148 DebugPrint((0, "CdRom%d: AutoPlay has lost it's irp and "
6149 "doesn't know where to find it. Leave it "
6150 "alone and it'll come home dragging it's "
6151 "stack behind it.\n",
6152 deviceExtension
->DeviceNumber
));
6153 cddata
->MediaChangeIrpLost
= TRUE
;
6162 // Process all generic timer IRPS in the timer list. As IRPs are pulled
6163 // off of the TimerIrpList they must be remembered in the first loop
6164 // if they are not sent to the lower driver. After all items have
6165 // been pulled off the list, it is possible to put the held IRPs back
6166 // into the TimerIrpList.
6170 if (IsListEmpty(&cddata
->TimerIrpList
)) {
6173 listEntry
= ExInterlockedRemoveHeadList(&cddata
->TimerIrpList
,
6174 &cddata
->TimerIrpSpinLock
);
6179 // There is something in the timer list. Pick up the IRP and
6180 // see if it is ready to be submitted.
6183 irp
= CONTAINING_RECORD(listEntry
, IRP
, Tail
.Overlay
.ListEntry
);
6184 irpStack
= IoGetCurrentIrpStackLocation(irp
);
6186 if (irpStack
->Parameters
.Others
.Argument3
) {
6190 // Decrement the countdown timer and put the IRP back in the list.
6193 count
= (ULONG_PTR
) irpStack
->Parameters
.Others
.Argument3
;
6195 irpStack
->Parameters
.Others
.Argument3
= (PVOID
) count
;
6197 ASSERT(irp
->AssociatedIrp
.MasterIrp
== NULL
);
6199 irp
->AssociatedIrp
.MasterIrp
= (PVOID
) heldIrpList
;
6206 // Submit this IRP to the lower driver. This IRP does not
6207 // need to be remembered here. It will be handled again when
6211 DebugPrint((1, "CdRomTickHandler: Reissuing request %lx (thread = %lx)\n", irp
, irp
->Tail
.Overlay
.Thread
));
6214 // feed this to the appropriate port driver
6217 IoCallDriver (deviceExtension
->PortDeviceObject
, irp
);
6222 // Pick up the next IRP from the timer list.
6225 listEntry
= ExInterlockedRemoveHeadList(&cddata
->TimerIrpList
,
6226 &cddata
->TimerIrpSpinLock
);
6230 // Move all held IRPs back onto the timer list.
6233 while (heldIrpList
) {
6236 // Save the single list pointer before queueing this IRP.
6239 nextIrp
= (PIRP
) heldIrpList
->AssociatedIrp
.MasterIrp
;
6240 heldIrpList
->AssociatedIrp
.MasterIrp
= NULL
;
6243 // Return the held IRP to the timer list.
6246 ExInterlockedInsertTailList(&cddata
->TimerIrpList
,
6247 &heldIrpList
->Tail
.Overlay
.ListEntry
,
6248 &cddata
->TimerIrpSpinLock
);
6251 // Continue processing the held IRPs
6254 heldIrpList
= nextIrp
;
6260 CdRomCheckRegistryForMediaChangeValue(
6261 IN PUNICODE_STRING RegistryPath
,
6262 IN ULONG DeviceNumber
6267 Routine Description:
6269 The user must specify that AutoPlay is to run on the platform
6270 by setting the registry value HKEY_LOCAL_MACHINE\System\CurrentControlSet\
6271 Services\Cdrom\Autorun:REG_DWORD:1.
6273 The user can override the global setting to enable or disable Autorun on a
6274 specific cdrom device by setting the key HKEY_LOCAL_MACHINE\System\
6275 CurrentControlSet\Services\Cdrom\Device<N>\Autorun:REG_DWORD to one or zero.
6276 (CURRENTLY UNIMPLEMENTED)
6278 If this registry value does not exist or contains the value zero then
6279 the timer to check for media change does not run.
6283 RegistryPath - pointer to the unicode string inside
6284 ...\CurrentControlSet\Services\Cdrom
6285 DeviceNumber - The number of the device object
6289 TRUE - Autorun is enabled.
6295 #define ITEMS_TO_QUERY 2 /* always 1 greater than what is searched */
6296 PRTL_QUERY_REGISTRY_TABLE parameters
= NULL
;
6304 ANSI_STRING paramNum
;
6306 UNICODE_STRING paramStr
;
6308 UNICODE_STRING paramSuffix
;
6309 UNICODE_STRING paramPath
;
6310 UNICODE_STRING paramDevPath
;
6313 // First append \Parameters to the passed in registry path
6316 RtlInitUnicodeString(¶mStr
, L
"\\Parameters");
6318 RtlInitUnicodeString(¶mPath
, NULL
);
6320 paramPath
.MaximumLength
= RegistryPath
->Length
+
6324 paramPath
.Buffer
= ExAllocatePool(PagedPool
, paramPath
.MaximumLength
);
6326 if(!paramPath
.Buffer
) {
6328 DebugPrint((1,"CdRomCheckRegAP: couldn't allocate paramPath\n"));
6333 RtlZeroMemory(paramPath
.Buffer
, paramPath
.MaximumLength
);
6334 RtlAppendUnicodeToString(¶mPath
, RegistryPath
->Buffer
);
6335 RtlAppendUnicodeToString(¶mPath
, paramStr
.Buffer
);
6337 DebugPrint((2, "CdRomCheckRegAP: paramPath [%d] = %ws\n",
6342 // build a counted ANSI string that contains
6343 // the suffix for the path
6346 sprintf(buf
, "\\Device%lu", DeviceNumber
);
6347 RtlInitAnsiString(¶mNum
, buf
);
6350 // Next convert this into a unicode string
6353 status
= RtlAnsiStringToUnicodeString(¶mSuffix
, ¶mNum
, TRUE
);
6355 if(!NT_SUCCESS(status
)) {
6356 DebugPrint((1,"CdRomCheckRegAP: couldn't convert paramNum to paramSuffix\n"));
6357 ExFreePool(paramPath
.Buffer
);
6361 RtlInitUnicodeString(¶mDevPath
, NULL
);
6364 // now build the device specific path
6367 paramDevPath
.MaximumLength
= paramPath
.Length
+
6368 paramSuffix
.Length
+
6370 paramDevPath
.Buffer
= ExAllocatePool(PagedPool
, paramDevPath
.MaximumLength
);
6372 if(!paramDevPath
.Buffer
) {
6373 RtlFreeUnicodeString(¶mSuffix
);
6374 ExFreePool(paramPath
.Buffer
);
6378 RtlZeroMemory(paramDevPath
.Buffer
, paramDevPath
.MaximumLength
);
6379 RtlAppendUnicodeToString(¶mDevPath
, paramPath
.Buffer
);
6380 RtlAppendUnicodeToString(¶mDevPath
, paramSuffix
.Buffer
);
6382 DebugPrint((2, "CdRomCheckRegAP: paramDevPath [%d] = %ws\n",
6386 parameters
= ExAllocatePool(NonPagedPool
,
6387 sizeof(RTL_QUERY_REGISTRY_TABLE
)*ITEMS_TO_QUERY
);
6392 // Check for the Autorun value.
6395 RtlZeroMemory(parameters
,
6396 (sizeof(RTL_QUERY_REGISTRY_TABLE
)*ITEMS_TO_QUERY
));
6398 parameters
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
6399 parameters
[0].Name
= L
"Autorun";
6400 parameters
[0].EntryContext
= &doRun
;
6401 parameters
[0].DefaultType
= REG_DWORD
;
6402 parameters
[0].DefaultData
= &zero
;
6403 parameters
[0].DefaultLength
= sizeof(ULONG
);
6405 status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
| RTL_REGISTRY_OPTIONAL
,
6406 RegistryPath
->Buffer
,
6411 DebugPrint((2, "CdRomCheckRegAP: cdrom/Autorun flag = %d\n", doRun
));
6413 RtlZeroMemory(parameters
,
6414 (sizeof(RTL_QUERY_REGISTRY_TABLE
)*ITEMS_TO_QUERY
));
6416 parameters
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
6417 parameters
[0].Name
= L
"Autorun";
6418 parameters
[0].EntryContext
= &tmp
;
6419 parameters
[0].DefaultType
= REG_DWORD
;
6420 parameters
[0].DefaultData
= &doRun
;
6421 parameters
[0].DefaultLength
= sizeof(ULONG
);
6423 status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
| RTL_REGISTRY_OPTIONAL
,
6429 DebugPrint((2, "CdRomCheckRegAP: cdrom/parameters/autorun flag = %d\n", tmp
));
6431 RtlZeroMemory(parameters
,
6432 (sizeof(RTL_QUERY_REGISTRY_TABLE
) * ITEMS_TO_QUERY
));
6434 parameters
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
6435 parameters
[0].Name
= L
"Autorun";
6436 parameters
[0].EntryContext
= &doRun
;
6437 parameters
[0].DefaultType
= REG_DWORD
;
6438 parameters
[0].DefaultData
= &tmp
;
6439 parameters
[0].DefaultLength
= sizeof(ULONG
);
6441 status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
| RTL_REGISTRY_OPTIONAL
,
6442 paramDevPath
.Buffer
,
6447 DebugPrint((1, "CdRomCheckRegAP: cdrom/parameters/device%d/autorun flag = %d\n", DeviceNumber
, doRun
));
6449 ExFreePool(parameters
);
6453 ExFreePool(paramPath
.Buffer
);
6454 ExFreePool(paramDevPath
.Buffer
);
6455 RtlFreeUnicodeString(¶mSuffix
);
6457 DebugPrint((1, "CdRomCheckRegAP: Autoplay for device %d is %s\n",
6459 (doRun
? "on" : "off")));
6472 IN PDEVICE_OBJECT DeviceObject
,
6479 Routine Description:
6481 This routine is called by DriverEntry to determine whether a Sanyo 3-CD
6482 changer device is present.
6486 DeviceObject - Supplies the device object for the 'real' device.
6492 TRUE - if an Atapi changer device is found.
6499 PCHAR inquiryBuffer
;
6500 IO_STATUS_BLOCK ioStatus
;
6502 PSCSI_ADAPTER_BUS_INFO adapterInfo
;
6504 PINQUIRYDATA inquiryData
;
6505 PSCSI_INQUIRY_DATA lunInfo
;
6507 inquiryBuffer
= ExAllocatePool(NonPagedPool
, 2048);
6508 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
6509 irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA
,
6522 status
= IoCallDriver(DeviceObject
, irp
);
6524 if (status
== STATUS_PENDING
) {
6525 KeWaitForSingleObject(&event
, Executive
, KernelMode
, FALSE
, NULL
);
6526 status
= ioStatus
.Status
;
6529 if (!NT_SUCCESS(status
)) {
6533 adapterInfo
= (PVOID
) inquiryBuffer
;
6535 for (scsiBus
=0; scsiBus
< (ULONG
)adapterInfo
->NumberOfBuses
; scsiBus
++) {
6538 // Get the SCSI bus scan data for this bus.
6541 lunInfo
= (PVOID
) (inquiryBuffer
+ adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
);
6545 if (lunInfo
->PathId
== PathId
&& lunInfo
->TargetId
== TargetId
) {
6547 inquiryData
= (PVOID
) lunInfo
->InquiryData
;
6549 if (RtlCompareMemory(inquiryData
->VendorId
, "TORiSAN CD-ROM CDR-C", 20) == 20) {
6550 ExFreePool(inquiryBuffer
);
6554 ExFreePool(inquiryBuffer
);
6558 if (!lunInfo
->NextInquiryDataOffset
) {
6562 lunInfo
= (PVOID
) (inquiryBuffer
+ lunInfo
->NextInquiryDataOffset
);
6566 ExFreePool(inquiryBuffer
);
6572 IsThisAnAtapiChanger(
6573 IN PDEVICE_OBJECT DeviceObject
,
6574 OUT PULONG DiscsPresent
6579 Routine Description:
6581 This routine is called by DriverEntry to determine whether an Atapi
6582 changer device is present.
6586 DeviceObject - Supplies the device object for the 'real' device.
6588 DiscsPresent - Supplies a pointer to the number of Discs supported by the changer.
6592 TRUE - if an Atapi changer device is found.
6597 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
6598 PMECHANICAL_STATUS_INFORMATION_HEADER mechanicalStatusBuffer
;
6600 SCSI_REQUEST_BLOCK srb
;
6601 PCDB cdb
= (PCDB
) &srb
.Cdb
[0];
6602 BOOLEAN retVal
= FALSE
;
6607 // Some devices can't handle 12 byte CDB's gracefully
6610 if(deviceExtension
->DeviceFlags
& DEV_NO_12BYTE_CDB
) {
6617 // Build and issue the mechanical status command.
6620 mechanicalStatusBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
6621 sizeof(MECHANICAL_STATUS_INFORMATION_HEADER
));
6623 if (!mechanicalStatusBuffer
) {
6628 // Build and send the Mechanism status CDB.
6631 RtlZeroMemory(&srb
, sizeof(srb
));
6634 srb
.TimeOutValue
= 20;
6636 cdb
->MECH_STATUS
.OperationCode
= SCSIOP_MECHANISM_STATUS
;
6637 cdb
->MECH_STATUS
.AllocationLength
[1] = sizeof(MECHANICAL_STATUS_INFORMATION_HEADER
);
6639 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
6641 mechanicalStatusBuffer
,
6642 sizeof(MECHANICAL_STATUS_INFORMATION_HEADER
),
6646 if (status
== STATUS_SUCCESS
) {
6649 // Indicate number of slots available
6652 *DiscsPresent
= mechanicalStatusBuffer
->NumberAvailableSlots
;
6653 if (*DiscsPresent
> 1) {
6658 // If only one disc, no need for this driver.
6666 // Device doesn't support this command.
6672 ExFreePool(mechanicalStatusBuffer
);
6680 IsThisAMultiLunDevice(
6681 IN PDEVICE_OBJECT DeviceObject
,
6682 IN PDEVICE_OBJECT PortDeviceObject
6686 Routine Description:
6688 This routine is called to determine whether a multi-lun
6693 DeviceObject - Supplies the device object for the 'real' device.
6697 TRUE - if a Multi-lun device is found.
6702 PSCSI_INQUIRY_DATA lunInfo
;
6703 PSCSI_ADAPTER_BUS_INFO adapterInfo
;
6704 PDEVICE_EXTENSION deviceExtension
= (PDEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
6705 PINQUIRYDATA inquiryData
;
6710 status
= ScsiClassGetInquiryData(PortDeviceObject
, (PSCSI_ADAPTER_BUS_INFO
*) &buffer
);
6712 if (!NT_SUCCESS(status
)) {
6713 DebugPrint((1,"IsThisAMultiLunDevice: ScsiClassGetInquiryData failed\n"));
6717 adapterInfo
= (PVOID
) buffer
;
6720 // For each SCSI bus this adapter supports ...
6723 for (scsiBus
=0; scsiBus
< adapterInfo
->NumberOfBuses
; scsiBus
++) {
6726 // Get the SCSI bus scan data for this bus.
6729 lunInfo
= (PVOID
) (buffer
+ adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
);
6731 while (adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
) {
6733 inquiryData
= (PVOID
)lunInfo
->InquiryData
;
6735 if ((lunInfo
->PathId
== deviceExtension
->PathId
) &&
6736 (lunInfo
->TargetId
== deviceExtension
->TargetId
) &&
6737 (inquiryData
->DeviceType
== READ_ONLY_DIRECT_ACCESS_DEVICE
)) {
6739 DebugPrint((1,"IsThisAMultiLunDevice: Vendor string is %.24s\n",
6740 inquiryData
->VendorId
));
6743 // If this device has more than one cdrom-type lun then we
6744 // won't support autoplay on it
6754 // Get next LunInfo.
6757 if (lunInfo
->NextInquiryDataOffset
== 0) {
6761 lunInfo
= (PVOID
) (buffer
+ lunInfo
->NextInquiryDataOffset
);
6770 IO_COMPLETION_ROUTINE CdRomUpdateGeometryCompletion
;
6773 CdRomUpdateGeometryCompletion(
6774 PDEVICE_OBJECT DeviceObject
,
6781 Routine Description:
6783 This routine andles the completion of the test unit ready irps
6784 used to determine if the media has changed. If the media has
6785 changed, this code signals the named event to wake up other
6786 system services that react to media change (aka AutoPlay).
6790 DeviceObject - the object for the completion
6791 Irp - the IRP being completed
6792 Context - the SRB from the IRP
6801 PSCSI_REQUEST_BLOCK srb
= (PSCSI_REQUEST_BLOCK
) Context
;
6802 PREAD_CAPACITY_DATA readCapacityBuffer
;
6803 PDEVICE_EXTENSION deviceExtension
;
6804 PIO_STACK_LOCATION irpStack
;
6807 ULONG_PTR retryCount
;
6813 // Get items saved in the private IRP stack location.
6816 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
6817 retryCount
= (ULONG_PTR
) irpStack
->Parameters
.Others
.Argument1
;
6818 originalIrp
= (PIRP
) irpStack
->Parameters
.Others
.Argument2
;
6820 if (!DeviceObject
) {
6821 DeviceObject
= irpStack
->DeviceObject
;
6823 ASSERT(DeviceObject
);
6825 deviceExtension
= DeviceObject
->DeviceExtension
;
6826 cddata
= (PCDROM_DATA
) (deviceExtension
+ 1);
6827 readCapacityBuffer
= srb
->DataBuffer
;
6829 if ((NT_SUCCESS(Irp
->IoStatus
.Status
)) && (SRB_STATUS(srb
->SrbStatus
) == SRB_STATUS_SUCCESS
)) {
6833 DebugPrint((2, "CdRomUpdateCapacityCompletion: [%lx] successful completion of buddy-irp %lx\n", originalIrp
, Irp
));
6835 // Copy sector size from read capacity buffer to device extension
6836 // in reverse byte order.
6839 from
= (PFOUR_BYTE
) &readCapacityBuffer
->BytesPerBlock
;
6840 to
= (PFOUR_BYTE
) &deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
;
6841 to
->Byte0
= from
->Byte3
;
6842 to
->Byte1
= from
->Byte2
;
6843 to
->Byte2
= from
->Byte1
;
6844 to
->Byte3
= from
->Byte0
;
6847 // Using the new BytesPerBlock, calculate and store the SectorShift.
6850 WHICH_BIT(deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
, deviceExtension
->SectorShift
);
6853 // Copy last sector in reverse byte order.
6856 from
= (PFOUR_BYTE
) &readCapacityBuffer
->LogicalBlockAddress
;
6857 to
= (PFOUR_BYTE
) &lastSector
;
6858 to
->Byte0
= from
->Byte3
;
6859 to
->Byte1
= from
->Byte2
;
6860 to
->Byte2
= from
->Byte1
;
6861 to
->Byte3
= from
->Byte0
;
6862 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(lastSector
+ 1);
6865 // Calculate number of cylinders.
6868 deviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
= (LONGLONG
)((lastSector
+ 1)/(32 * 64));
6869 deviceExtension
->PartitionLength
.QuadPart
=
6870 (deviceExtension
->PartitionLength
.QuadPart
<< deviceExtension
->SectorShift
);
6871 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= RemovableMedia
;
6874 // Assume sectors per track are 32;
6877 deviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
= 32;
6880 // Assume tracks per cylinder (number of heads) is 64.
6883 deviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
= 64;
6887 DebugPrint((1, "CdRomUpdateCapacityCompletion: [%lx] unsuccessful completion of buddy-irp %lx (status - %lx)\n", originalIrp
, Irp
, Irp
->IoStatus
.Status
));
6889 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
6890 ScsiClassReleaseQueue(DeviceObject
);
6893 retry
= ScsiClassInterpretSenseInfo(DeviceObject
,
6904 DebugPrint((1, "CdRomUpdateCapacityCompletion: [%lx] Retrying request %lx .. thread is %lx\n", originalIrp
, Irp
, Irp
->Tail
.Overlay
.Thread
));
6906 // set up a one shot timer to get this process started over
6909 irpStack
->Parameters
.Others
.Argument1
= (PVOID
) retryCount
;
6910 irpStack
->Parameters
.Others
.Argument2
= (PVOID
) originalIrp
;
6911 irpStack
->Parameters
.Others
.Argument3
= (PVOID
) 2;
6914 // Setup the IRP to be submitted again in the timer routine.
6917 irpStack
= IoGetNextIrpStackLocation(Irp
);
6918 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
6919 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
6920 irpStack
->Parameters
.Scsi
.Srb
= srb
;
6921 IoSetCompletionRoutine(Irp
,
6922 CdRomUpdateGeometryCompletion
,
6929 // Set up the SRB for read capacity.
6932 srb
->CdbLength
= 10;
6933 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
6934 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
6936 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
6937 srb
->PathId
= deviceExtension
->PathId
;
6938 srb
->TargetId
= deviceExtension
->TargetId
;
6939 srb
->Lun
= deviceExtension
->Lun
;
6940 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
6941 srb
->SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
6942 srb
->DataTransferLength
= sizeof(READ_CAPACITY_DATA
);
6948 cdb
= (PCDB
) &srb
->Cdb
[0];
6949 cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
6950 cdb
->CDB10
.LogicalUnitNumber
= deviceExtension
->Lun
;
6953 // Requests queued onto this list will be sent to the
6954 // lower level driver during CdRomTickHandler
6957 ExInterlockedInsertHeadList(&cddata
->TimerIrpList
,
6958 &Irp
->Tail
.Overlay
.ListEntry
,
6959 &cddata
->TimerIrpSpinLock
);
6961 return STATUS_MORE_PROCESSING_REQUIRED
;
6965 // This has been bounced for a number of times. Error the
6966 // original request.
6969 originalIrp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
6970 RtlZeroMemory(deviceExtension
->DiskGeometry
, sizeof(DISK_GEOMETRY_EX
));
6971 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= 2048;
6972 deviceExtension
->SectorShift
= 11;
6973 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(0x7fffffff);
6974 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= RemovableMedia
;
6979 // Set up reasonable defaults
6982 RtlZeroMemory(deviceExtension
->DiskGeometry
, sizeof(DISK_GEOMETRY_EX
));
6983 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= 2048;
6984 deviceExtension
->SectorShift
= 11;
6985 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(0x7fffffff);
6986 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= RemovableMedia
;
6991 // Free resources held.
6994 ExFreePool(srb
->SenseInfoBuffer
);
6995 ExFreePool(srb
->DataBuffer
);
6997 if (Irp
->MdlAddress
) {
6998 IoFreeMdl(Irp
->MdlAddress
);
7001 if (originalIrp
->Tail
.Overlay
.Thread
) {
7003 DebugPrint((2, "CdRomUpdateCapacityCompletion: [%lx] completing original IRP\n", originalIrp
));
7004 IoCompleteRequest(originalIrp
, IO_DISK_INCREMENT
);
7007 DebugPrint((1, "CdRomUpdateCapacityCompletion: [%lx] original irp has "
7014 // It's now safe to either start the next request or let the waiting ioctl
7015 // request continue along it's merry way
7018 IoStartNextPacket(DeviceObject
, FALSE
);
7020 return STATUS_MORE_PROCESSING_REQUIRED
;
7025 CdRomUpdateCapacity(
7026 IN PDEVICE_EXTENSION DeviceExtension
,
7027 IN PIRP IrpToComplete
,
7028 IN OPTIONAL PKEVENT IoctlEvent
7033 Routine Description:
7035 This routine updates the capacity of the disk as recorded in the device extension.
7036 It also completes the IRP given with STATUS_VERIFY_REQUIRED. This routine is called
7037 when a media change has occurred and it is necessary to determine the capacity of the
7038 new media prior to the next access.
7042 DeviceExtension - the device to update
7043 IrpToComplete - the request that needs to be completed when done.
7054 PSCSI_REQUEST_BLOCK srb
;
7055 PREAD_CAPACITY_DATA capacityBuffer
;
7056 PIO_STACK_LOCATION irpStack
;
7059 irp
= IoAllocateIrp((CCHAR
)(DeviceExtension
->DeviceObject
->StackSize
+1),
7064 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
7066 capacityBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
7067 sizeof(READ_CAPACITY_DATA
));
7069 if (capacityBuffer
) {
7072 senseBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
7076 irp
->MdlAddress
= IoAllocateMdl(capacityBuffer
,
7077 sizeof(READ_CAPACITY_DATA
),
7082 if (irp
->MdlAddress
) {
7085 // Have all resources. Set up the IRP to send for the capacity.
7088 IoSetNextIrpStackLocation(irp
);
7089 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
7090 irp
->IoStatus
.Information
= 0;
7092 irp
->UserBuffer
= NULL
;
7095 // Save the device object and retry count in a private stack location.
7098 irpStack
= IoGetCurrentIrpStackLocation(irp
);
7099 irpStack
->DeviceObject
= DeviceExtension
->DeviceObject
;
7100 irpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
7101 irpStack
->Parameters
.Others
.Argument2
= (PVOID
) IrpToComplete
;
7104 // Construct the IRP stack for the lower level driver.
7107 irpStack
= IoGetNextIrpStackLocation(irp
);
7108 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
7109 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
7110 irpStack
->Parameters
.Scsi
.Srb
= srb
;
7111 IoSetCompletionRoutine(irp
,
7112 CdRomUpdateGeometryCompletion
,
7121 MmBuildMdlForNonPagedPool(irp
->MdlAddress
);
7125 // Set up the SRB for read capacity.
7128 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
7129 RtlZeroMemory(senseBuffer
, SENSE_BUFFER_SIZE
);
7130 srb
->CdbLength
= 10;
7131 srb
->TimeOutValue
= DeviceExtension
->TimeOutValue
;
7132 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
7134 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
7135 srb
->PathId
= DeviceExtension
->PathId
;
7136 srb
->TargetId
= DeviceExtension
->TargetId
;
7137 srb
->Lun
= DeviceExtension
->Lun
;
7138 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
7139 srb
->SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
7140 srb
->DataBuffer
= capacityBuffer
;
7141 srb
->DataTransferLength
= sizeof(READ_CAPACITY_DATA
);
7142 srb
->OriginalRequest
= irp
;
7143 srb
->SenseInfoBuffer
= senseBuffer
;
7144 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
7150 cdb
= (PCDB
) &srb
->Cdb
[0];
7151 cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
7152 cdb
->CDB10
.LogicalUnitNumber
= DeviceExtension
->Lun
;
7155 // Set the return value in the IRP that will be completed
7156 // upon completion of the read capacity.
7159 IrpToComplete
->IoStatus
.Status
= STATUS_IO_DEVICE_ERROR
;
7160 IoMarkIrpPending(IrpToComplete
);
7162 IoCallDriver(DeviceExtension
->PortDeviceObject
, irp
);
7165 // status is not checked because the completion routine for this
7166 // IRP will always get called and it will free the resources.
7169 return STATUS_PENDING
;
7172 ExFreePool(senseBuffer
);
7173 ExFreePool(capacityBuffer
);
7178 ExFreePool(capacityBuffer
);
7191 return STATUS_INSUFFICIENT_RESOURCES
;
7196 CdRomClassIoctlCompletion(
7197 IN PDEVICE_OBJECT DeviceObject
,
7204 Routine Description:
7206 This routine signals the event used by CdRomDeviceControl to synchronize
7207 class driver (and lower level driver) ioctls with cdrom's startio routine.
7208 The irp completion is short-circuited so that CdRomDeviceControl can
7209 reissue it once it wakes up.
7213 DeviceObject - the device object
7214 Irp - the request we are synchronizing
7215 Context - a PKEVENT that we need to signal
7224 PKEVENT syncEvent
= (PKEVENT
) Context
;
7226 DebugPrint((2, "CdRomClassIoctlCompletion: setting event for irp %#08lx\n",
7230 KeSetEvent(syncEvent
, IO_DISK_INCREMENT
, FALSE
);
7232 return STATUS_MORE_PROCESSING_REQUIRED
;