2 * PROJECT: ReactOS Storage Stack
3 * LICENSE: DDK - see license.txt in the root dir
4 * FILE: drivers/storage/cdrom/cdrom.c
5 * PURPOSE: CDROM driver
6 * PROGRAMMERS: Based on a source code sample from Microsoft NT4 DDK
15 #include <include/class2.h>
21 #define CDB12GENERIC_LENGTH 12
23 typedef struct _XA_CONTEXT
{
26 // Pointer to the device object.
29 PDEVICE_OBJECT DeviceObject
;
32 // Pointer to the original request when
33 // a mode select must be sent.
39 // Pointer to the mode select srb.
42 PSCSI_REQUEST_BLOCK Srb
;
43 } XA_CONTEXT
, *PXA_CONTEXT
;
45 typedef struct _ERROR_RECOVERY_DATA
{
46 MODE_PARAMETER_HEADER Header
;
47 MODE_PARAMETER_BLOCK BlockDescriptor
;
48 MODE_READ_RECOVERY_PAGE ReadRecoveryPage
;
49 } ERROR_RECOVERY_DATA
, *PERROR_RECOVERY_DATA
;
51 typedef struct _ERROR_RECOVERY_DATA10
{
52 MODE_PARAMETER_HEADER10 Header10
;
53 MODE_PARAMETER_BLOCK BlockDescriptor10
;
54 MODE_READ_RECOVERY_PAGE ReadRecoveryPage10
;
55 } ERROR_RECOVERY_DATA10
, *PERROR_RECOVERY_DATA10
;
58 // CdRom specific addition to device extension.
61 typedef struct _CDROM_DATA
{
64 // Indicates whether an audio play operation
65 // is currently being performed.
71 // Indicates whether the blocksize used for user data
78 // Indicates whether 6 or 10 byte mode sense/select
85 // Storage for the error recovery page. This is used
86 // as an easy method to switch block sizes.
90 ERROR_RECOVERY_DATA u1
;
91 ERROR_RECOVERY_DATA10 u2
;
96 // Pointer to the original irp for the raw read.
102 // Used to protect accesses to the RawAccess flag.
105 KSPIN_LOCK FormSpinLock
;
108 // Even if media change support is requested, there are some devices
109 // that are not supported. This flag will indicate that such a device
110 // is present when it is FALSE.
113 BOOLEAN MediaChangeSupported
;
116 // The media change event is being supported. The media change timer
117 // should be running whenever this is true.
123 // The timer value to support media change events. This is a countdown
124 // value used to determine when to poll the device for a media change.
125 // The max value for the timer is 255 seconds.
128 UCHAR MediaChangeCountDown
;
132 // Second timer to keep track of how long the media change IRP has been
133 // in use. If this value exceeds the timeout (#defined) then we should
134 // print out a message to the user and set the MediaChangeIrpLost flag
137 SHORT MediaChangeIrpTimeInUse
;
140 // Set by CdRomTickHandler when we determine that the media change irp has
144 BOOLEAN MediaChangeIrpLost
;
147 UCHAR PadReserve
; // use this for new flags.
150 // An IRP is allocated and kept for the duration that media change
151 // detection is in effect. If this is NULL and MediaChange is TRUE,
152 // the detection is in progress. This should always be NULL when
153 // MediaChange is FALSE.
159 // The timer work list is a collection of IRPS that are prepared for
160 // submission, but need to allow some time to pass before they are
164 LIST_ENTRY TimerIrpList
;
165 KSPIN_LOCK TimerIrpSpinLock
;
167 } CDROM_DATA
, *PCDROM_DATA
;
169 #define DEVICE_EXTENSION_SIZE sizeof(DEVICE_EXTENSION) + sizeof(CDROM_DATA)
170 #define SCSI_CDROM_TIMEOUT 10
171 #define SCSI_CHANGER_BONUS_TIMEOUT 10
172 #define HITACHI_MODE_DATA_SIZE 12
173 #define MODE_DATA_SIZE 64
174 #define RAW_SECTOR_SIZE 2352
175 #define COOKED_SECTOR_SIZE 2048
176 #define MEDIA_CHANGE_DEFAULT_TIME 4
177 #define CDROM_SRB_LIST_SIZE 4
183 // Used to detect the loss of the autorun irp. The driver prints out a message
184 // (debug level 0) if this timeout ever occurs
186 #define MEDIA_CHANGE_TIMEOUT_TIME 300
190 #define PLAY_ACTIVE(DeviceExtension) (((PCDROM_DATA)(DeviceExtension + 1))->PlayActive)
192 #define MSF_TO_LBA(Minutes,Seconds,Frames) \
193 (ULONG)((60 * 75 * (Minutes)) + (75 * (Seconds)) + ((Frames) - 150))
195 #define LBA_TO_MSF(Lba,Minutes,Seconds,Frames) \
197 (Minutes) = (UCHAR)(Lba / (60 * 75)); \
198 (Seconds) = (UCHAR)((Lba % (60 * 75)) / 75); \
199 (Frames) = (UCHAR)((Lba % (60 * 75)) % 75); \
202 #define DEC_TO_BCD(x) (((x / 10) << 4) + (x % 10))
205 // Define flags for XA, CDDA, and Mode Select/Sense
208 #define XA_USE_6_BYTE 0x01
209 #define XA_USE_10_BYTE 0x02
210 #define XA_USE_READ_CD 0x04
211 #define XA_NOT_SUPPORTED 0x08
213 #define PLEXTOR_CDDA 0x10
214 #define NEC_CDDA 0x20
217 // Sector types for READ_CD
221 #define CD_DA_SECTOR 1
222 #define YELLOW_MODE1_SECTOR 2
223 #define YELLOW_MODE2_SECTOR 3
224 #define FORM2_MODE1_SECTOR 4
225 #define FORM2_MODE2_SECTOR 5
229 #ifdef ExAllocatePool
230 #undef ExAllocatePool
232 #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'CscS')
238 IN PDRIVER_OBJECT DriverObject
,
239 IN PUNICODE_STRING RegistryPath
244 ScsiCdRomFindDevices(
245 IN PDRIVER_OBJECT DriverObject
,
246 IN PUNICODE_STRING RegistryPath
,
247 IN PCLASS_INIT_DATA InitializationData
,
248 IN PDEVICE_OBJECT PortDeviceObject
,
255 IN PDEVICE_OBJECT DeviceObject
,
261 ScsiCdRomReadVerification(
262 IN PDEVICE_OBJECT DeviceObject
,
269 IN PDEVICE_OBJECT DeviceObject
,
271 IN PIRP OriginalRequest
277 IN PDEVICE_OBJECT DeviceObject
,
281 IO_COMPLETION_ROUTINE CdRomDeviceControlCompletion
;
284 CdRomDeviceControlCompletion(
285 IN PDEVICE_OBJECT DeviceObject
,
290 IO_COMPLETION_ROUTINE CdRomSetVolumeIntermediateCompletion
;
293 CdRomSetVolumeIntermediateCompletion(
294 IN PDEVICE_OBJECT DeviceObject
,
299 IO_COMPLETION_ROUTINE CdRomSwitchModeCompletion
;
302 CdRomSwitchModeCompletion(
303 IN PDEVICE_OBJECT DeviceObject
,
308 IO_COMPLETION_ROUTINE CdRomXACompletion
;
312 IN PDEVICE_OBJECT DeviceObject
,
317 IO_COMPLETION_ROUTINE CdRomClassIoctlCompletion
;
320 CdRomClassIoctlCompletion(
321 IN PDEVICE_OBJECT DeviceObject
,
329 IN PDEVICE_OBJECT DeviceObject
,
336 IN PDEVICE_OBJECT DeviceObject
,
342 CdRomCheckRegistryForMediaChangeValue(
343 IN PUNICODE_STRING RegistryPath
,
344 IN ULONG DeviceNumber
350 IN PDEVICE_EXTENSION DeviceExtension
,
351 IN PIRP IrpToComplete
,
352 IN OPTIONAL PKEVENT IoctlEvent
357 CreateCdRomDeviceObject(
358 IN PDRIVER_OBJECT DriverObject
,
359 IN PDEVICE_OBJECT PortDeviceObject
,
361 IN PULONG DeviceCount
,
362 PIO_SCSI_CAPABILITIES PortCapabilities
,
363 IN PSCSI_INQUIRY_DATA LunInfo
,
364 IN PCLASS_INIT_DATA InitializationData
,
365 IN PUNICODE_STRING RegistryPath
371 PDEVICE_OBJECT DeviceObject
,
372 PINQUIRYDATA InquiryData
,
373 PIO_SCSI_CAPABILITIES PortCapabilities
379 IN PDEVICE_OBJECT DeviceObject
385 PDEVICE_OBJECT DeviceObject
,
386 PSCSI_REQUEST_BLOCK Srb
,
391 IO_COMPLETION_ROUTINE ToshibaProcessErrorCompletion
;
395 PDEVICE_OBJECT DeviceObject
,
396 PSCSI_REQUEST_BLOCK Srb
,
403 IsThisAnAtapiChanger(
404 IN PDEVICE_OBJECT DeviceObject
,
405 OUT PULONG DiscsPresent
411 IN PDEVICE_OBJECT DeviceObject
,
418 IsThisAMultiLunDevice(
419 IN PDEVICE_OBJECT DeviceObject
,
420 IN PDEVICE_OBJECT PortDeviceObject
425 CdRomCreateNamedEvent(
426 IN PDEVICE_EXTENSION DeviceExtension
,
427 IN ULONG DeviceNumber
434 IN UNICODE_STRING ScsiUnicodeString
[],
435 OUT PUCHAR IntermediateController
440 #pragma alloc_text(PAGE, DriverEntry)
441 #pragma alloc_text(PAGE, ScsiCdRomFindDevices)
442 #pragma alloc_text(PAGE, CreateCdRomDeviceObject)
443 #pragma alloc_text(PAGE, ScanForSpecial)
444 //#pragma alloc_text(PAGE, CdRomDeviceControl)
445 #pragma alloc_text(PAGE, HitachProcessError)
446 #pragma alloc_text(PAGE, CdRomIsPlayActive)
447 #pragma alloc_text(PAGE, ScsiCdRomReadVerification)
448 #pragma alloc_text(INIT, CdRomCheckRegistryForMediaChangeValue)
449 #pragma alloc_text(INIT, IsThisAnAtapiChanger)
450 #pragma alloc_text(INIT, IsThisASanyo)
451 #pragma alloc_text(INIT, IsThisAMultiLunDevice)
452 #pragma alloc_text(INIT, CdRomCreateNamedEvent)
454 #pragma alloc_text(PAGE, FindScsiAdapter)
463 IN PDRIVER_OBJECT DriverObject
,
464 IN PUNICODE_STRING RegistryPath
471 This routine initializes the cdrom class driver.
475 DriverObject - Pointer to driver object created by system.
477 RegistryPath - Pointer to the name of the services node for this driver.
481 The function value is the final status from the initialization operation.
486 CLASS_INIT_DATA InitializationData
;
489 return STATUS_NO_SUCH_DEVICE
;
496 RtlZeroMemory (&InitializationData
, sizeof(CLASS_INIT_DATA
));
502 InitializationData
.InitializationDataSize
= sizeof(CLASS_INIT_DATA
);
503 InitializationData
.DeviceExtensionSize
= DEVICE_EXTENSION_SIZE
;
505 InitializationData
.DeviceType
= FILE_DEVICE_CD_ROM
;
506 InitializationData
.DeviceCharacteristics
= FILE_REMOVABLE_MEDIA
| FILE_READ_ONLY_DEVICE
;
512 InitializationData
.ClassReadWriteVerification
= ScsiCdRomReadVerification
;
513 InitializationData
.ClassDeviceControl
= CdRomDeviceControl
;
514 InitializationData
.ClassFindDevices
= ScsiCdRomFindDevices
;
515 InitializationData
.ClassShutdownFlush
= NULL
;
516 InitializationData
.ClassCreateClose
= NULL
;
517 InitializationData
.ClassStartIo
= ScsiCdRomStartIo
;
520 // Call the class init routine
523 return ScsiClassInitialize( DriverObject
, RegistryPath
, &InitializationData
);
525 } // end DriverEntry()
529 ScsiCdRomFindDevices(
530 IN PDRIVER_OBJECT DriverObject
,
531 IN PUNICODE_STRING RegistryPath
,
532 IN PCLASS_INIT_DATA InitializationData
,
533 IN PDEVICE_OBJECT PortDeviceObject
,
541 Connect to SCSI port driver. Get adapter capabilities and
542 SCSI bus configuration information. Search inquiry data
543 for CDROM devices to process.
547 DriverObject - CDROM class driver object.
548 PortDeviceObject - SCSI port driver device object.
549 PortNumber - The system ordinal for this scsi adapter.
553 TRUE if CDROM device present on this SCSI adapter.
558 PIO_SCSI_CAPABILITIES portCapabilities
;
561 PSCSI_INQUIRY_DATA lunInfo
;
562 PSCSI_ADAPTER_BUS_INFO adapterInfo
;
563 PINQUIRYDATA inquiryData
;
566 BOOLEAN foundDevice
= FALSE
;
569 // Call port driver to get adapter capabilities.
572 status
= ScsiClassGetCapabilities(PortDeviceObject
, &portCapabilities
);
574 if (!NT_SUCCESS(status
)) {
575 DebugPrint((1,"FindScsiDevices: ScsiClassGetCapabilities failed\n"));
580 // Call port driver to get inquiry information to find cdroms.
583 status
= ScsiClassGetInquiryData(PortDeviceObject
, (PSCSI_ADAPTER_BUS_INFO
*) &buffer
);
585 if (!NT_SUCCESS(status
)) {
586 DebugPrint((1,"FindScsiDevices: ScsiClassGetInquiryData failed\n"));
591 // Get the address of the count of the number of cdroms already initialized.
594 cdRomCount
= &IoGetConfigurationInformation()->CdRomCount
;
595 adapterInfo
= (PVOID
) buffer
;
598 // For each SCSI bus this adapter supports ...
601 for (scsiBus
=0; scsiBus
< adapterInfo
->NumberOfBuses
; scsiBus
++) {
604 // Get the SCSI bus scan data for this bus.
607 lunInfo
= (PVOID
) (buffer
+ adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
);
610 // Search list for unclaimed disk devices.
613 while (adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
) {
615 inquiryData
= (PVOID
)lunInfo
->InquiryData
;
617 if ((inquiryData
->DeviceType
== READ_ONLY_DIRECT_ACCESS_DEVICE
) &&
618 (inquiryData
->DeviceTypeQualifier
== 0) &&
619 (!lunInfo
->DeviceClaimed
)) {
621 DebugPrint((1,"FindScsiDevices: Vendor string is %.24s\n",
622 inquiryData
->VendorId
));
625 // Create device objects for cdrom
628 status
= CreateCdRomDeviceObject(DriverObject
,
637 if (NT_SUCCESS(status
)) {
640 // Increment system cdrom device count.
646 // Indicate that a cdrom device was found.
657 if (lunInfo
->NextInquiryDataOffset
== 0) {
661 lunInfo
= (PVOID
) (buffer
+ lunInfo
->NextInquiryDataOffset
);
670 } // end FindScsiCdRoms()
674 CdRomCreateNamedEvent(
675 IN PDEVICE_EXTENSION DeviceExtension
,
676 IN ULONG DeviceNumber
683 Create the named synchronization event for notification of media change
684 events to the system. The event is reset before this function returns.
688 DeviceExtension - the device extension pointer for storage of the event pointer.
697 UNICODE_STRING unicodeString
;
698 OBJECT_ATTRIBUTES objectAttributes
;
699 CCHAR eventNameBuffer
[MAXIMUM_FILENAME_LENGTH
];
700 STRING eventNameString
;
705 sprintf(eventNameBuffer
,"\\Device\\MediaChangeEvent%ld",
708 RtlInitString(&eventNameString
,
711 status
= RtlAnsiStringToUnicodeString(&unicodeString
,
715 if (!NT_SUCCESS(status
)) {
719 InitializeObjectAttributes(&objectAttributes
,
721 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
725 DeviceExtension
->MediaChangeEvent
= IoCreateSynchronizationEvent(&unicodeString
,
727 DeviceExtension
->MediaChangeEventHandle
= handle
;
729 KeClearEvent(DeviceExtension
->MediaChangeEvent
);
731 RtlFreeUnicodeString(&unicodeString
);
736 CreateCdRomDeviceObject(
737 IN PDRIVER_OBJECT DriverObject
,
738 IN PDEVICE_OBJECT PortDeviceObject
,
740 IN PULONG DeviceCount
,
741 IN PIO_SCSI_CAPABILITIES PortCapabilities
,
742 IN PSCSI_INQUIRY_DATA LunInfo
,
743 IN PCLASS_INIT_DATA InitializationData
,
744 IN PUNICODE_STRING RegistryPath
751 This routine creates an object for the device and then calls the
752 SCSI port driver for media capacity and sector size.
756 DriverObject - Pointer to driver object created by system.
757 PortDeviceObject - to connect to SCSI port driver.
758 DeviceCount - Number of previously installed CDROMs.
759 PortCapabilities - Pointer to structure returned by SCSI port
760 driver describing adapter capabilites (and limitations).
761 LunInfo - Pointer to configuration information for this device.
769 CHAR ntNameBuffer
[64];
771 BOOLEAN changerDevice
;
772 SCSI_REQUEST_BLOCK srb
;
776 PVOID senseData
= NULL
;
777 PDEVICE_OBJECT deviceObject
= NULL
;
778 PDEVICE_EXTENSION deviceExtension
= NULL
;
783 BOOLEAN srbListInitialized
= FALSE
;
786 // Claim the device. Note that any errors after this
787 // will goto the generic handler, where the device will
791 status
= ScsiClassClaimDevice(PortDeviceObject
,
796 if (!NT_SUCCESS(status
)) {
801 // Create device object for this device.
804 sprintf(ntNameBuffer
,
805 "\\Device\\CdRom%lu",
808 status
= ScsiClassCreateDeviceObject(DriverObject
,
814 if (!NT_SUCCESS(status
)) {
815 DebugPrint((1,"CreateCdRomDeviceObjects: Can not create device %s\n",
818 goto CreateCdRomDeviceObjectExit
;
822 // Indicate that IRPs should include MDLs.
825 deviceObject
->Flags
|= DO_DIRECT_IO
;
828 // Set up required stack size in device object.
831 deviceObject
->StackSize
= PortDeviceObject
->StackSize
+ 2;
833 deviceExtension
= deviceObject
->DeviceExtension
;
836 // Allocate spinlock for split request completion.
839 KeInitializeSpinLock(&deviceExtension
->SplitRequestSpinLock
);
842 // This is the physical device.
845 deviceExtension
->PhysicalDevice
= deviceObject
;
848 // Initialize lock count to zero. The lock count is used to
849 // disable the ejection mechanism when media is mounted.
852 deviceExtension
->LockCount
= 0;
855 // Save system cdrom number
858 deviceExtension
->DeviceNumber
= *DeviceCount
;
861 // Copy port device object to device extension.
864 deviceExtension
->PortDeviceObject
= PortDeviceObject
;
867 // Set the alignment requirements for the device based on the
868 // host adapter requirements
871 if (PortDeviceObject
->AlignmentRequirement
> deviceObject
->AlignmentRequirement
) {
872 deviceObject
->AlignmentRequirement
= PortDeviceObject
->AlignmentRequirement
;
876 // Save address of port driver capabilities.
879 deviceExtension
->PortCapabilities
= PortCapabilities
;
885 deviceExtension
->SrbFlags
= 0;
886 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
889 // Allocate request sense buffer.
892 senseData
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
894 if (senseData
== NULL
) {
897 // The buffer cannot be allocated.
900 status
= STATUS_INSUFFICIENT_RESOURCES
;
901 goto CreateCdRomDeviceObjectExit
;
905 // Set the sense data pointer in the device extension.
908 deviceExtension
->SenseData
= senseData
;
911 // CDROMs are not partitionable so starting offset is 0.
914 deviceExtension
->StartingOffset
.LowPart
= 0;
915 deviceExtension
->StartingOffset
.HighPart
= 0;
918 // Path/TargetId/LUN describes a device location on the SCSI bus.
919 // This information comes from the LunInfo buffer.
922 deviceExtension
->PortNumber
= (UCHAR
)PortNumber
;
923 deviceExtension
->PathId
= LunInfo
->PathId
;
924 deviceExtension
->TargetId
= LunInfo
->TargetId
;
925 deviceExtension
->Lun
= LunInfo
->Lun
;
928 // Set timeout value in seconds.
931 timeOut
= ScsiClassQueryTimeOutRegistryValue(RegistryPath
);
933 deviceExtension
->TimeOutValue
= timeOut
;
935 deviceExtension
->TimeOutValue
= SCSI_CDROM_TIMEOUT
;
939 // Build the lookaside list for srb's for the physical disk. Should only
943 ScsiClassInitializeSrbLookasideList(deviceExtension
,
944 CDROM_SRB_LIST_SIZE
);
946 srbListInitialized
= TRUE
;
949 // Back pointer to device object.
952 deviceExtension
->DeviceObject
= deviceObject
;
955 // Allocate buffer for drive geometry.
958 deviceExtension
->DiskGeometry
=
959 ExAllocatePool(NonPagedPool
, sizeof(DISK_GEOMETRY_EX
));
961 if (deviceExtension
->DiskGeometry
== NULL
) {
963 status
= STATUS_INSUFFICIENT_RESOURCES
;
964 goto CreateCdRomDeviceObjectExit
;
968 // Set up media change support defaults.
971 cddata
= (PCDROM_DATA
)(deviceExtension
+ 1);
973 KeInitializeSpinLock(&cddata
->FormSpinLock
);
974 KeInitializeSpinLock(&cddata
->TimerIrpSpinLock
);
975 InitializeListHead(&cddata
->TimerIrpList
);
977 cddata
->MediaChangeCountDown
= MEDIA_CHANGE_DEFAULT_TIME
;
978 cddata
->MediaChangeSupported
= FALSE
;
979 cddata
->MediaChange
= FALSE
;
982 // Assume that there is initially no media in the device
983 // only notify upper layers if there is something there
986 deviceExtension
->MediaChangeNoMedia
= TRUE
;
987 cddata
->MediaChangeIrp
= NULL
;
989 cddata
->MediaChangeIrpTimeInUse
= 0;
990 cddata
->MediaChangeIrpLost
= FALSE
;
994 // Scan for Scsi controllers that require special processing.
997 ScanForSpecial(deviceObject
,
998 (PINQUIRYDATA
) LunInfo
->InquiryData
,
1002 // Do READ CAPACITY. This SCSI command
1003 // returns the last sector address on the device
1004 // and the bytes per sector.
1005 // These are used to calculate the drive capacity
1009 status
= ScsiClassReadDriveCapacity(deviceObject
);
1010 bps
= deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
;
1012 if (!NT_SUCCESS(status
) || !bps
) {
1015 "CreateCdRomDeviceObjects: Can't read capacity for device %s\n",
1019 // Set disk geometry to default values (per ISO 9660).
1023 deviceExtension
->SectorShift
= 11;
1024 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(0x7fffffff);
1028 // Insure that bytes per sector is a power of 2
1029 // This corrects a problem with the HP 4020i CDR where it
1030 // returns an incorrect number for bytes per sector.
1033 lastBit
= (ULONG
) -1;
1041 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= bps
;
1042 DebugPrint((2, "CreateCdRomDeviceObject: Calc'd bps = %x\n", bps
));
1045 // Check to see if this is some sort of changer device
1048 changerDevice
= FALSE
;
1051 // Search for devices that have special requirements for media
1055 if (deviceExtension
->Lun
> 0) {
1056 changerDevice
= TRUE
;
1059 if (!changerDevice
) {
1060 changerDevice
= IsThisASanyo(deviceObject
, deviceExtension
->PathId
,
1061 deviceExtension
->TargetId
);
1064 if (!changerDevice
) {
1066 changerDevice
= IsThisAnAtapiChanger(deviceObject
, &tmp
);
1069 if (!changerDevice
) {
1070 changerDevice
= IsThisAMultiLunDevice(deviceObject
, PortDeviceObject
);
1074 // If it is a changer device, increment the timeout to take platter-swapping
1075 // time into account
1079 deviceExtension
->TimeOutValue
+= SCSI_CHANGER_BONUS_TIMEOUT
;
1083 // Create the media change named event. If this succeeds then continue
1084 // initializing the media change support data items.
1087 CdRomCreateNamedEvent(deviceExtension
,*DeviceCount
);
1088 if (deviceExtension
->MediaChangeEvent
) {
1091 // If this is not a changer, get an IRP for the timer request
1092 // and initialize the timer.
1095 if (!changerDevice
) {
1098 // Not a changer device - continue with media change initialization.
1099 // Determine if the user actually wants media change events.
1102 if (CdRomCheckRegistryForMediaChangeValue(RegistryPath
, *DeviceCount
)) {
1103 PIO_STACK_LOCATION irpStack
;
1104 PSCSI_REQUEST_BLOCK srb
;
1108 // User wants it - preallocate IRP and SRB.
1111 irp
= IoAllocateIrp((CCHAR
)(deviceObject
->StackSize
+1),
1116 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
1117 buffer
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
1119 if (srb
&& buffer
) {
1123 // All resources have been allocated set up the IRP.
1126 IoSetNextIrpStackLocation(irp
);
1127 irpStack
= IoGetCurrentIrpStackLocation(irp
);
1128 irpStack
->DeviceObject
= deviceObject
;
1129 irpStack
= IoGetNextIrpStackLocation(irp
);
1130 cddata
->MediaChangeIrp
= irp
;
1131 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1134 // Initialize the SRB
1137 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
1140 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
* 2;
1141 srb
->QueueTag
= SP_UNTAGGED
;
1142 srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
1143 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1144 srb
->PathId
= deviceExtension
->PathId
;
1145 srb
->TargetId
= deviceExtension
->TargetId
;
1146 srb
->Lun
= deviceExtension
->Lun
;
1147 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1150 // Initialize and set up the sense information buffer
1153 RtlZeroMemory(buffer
, SENSE_BUFFER_SIZE
);
1154 srb
->SenseInfoBuffer
= buffer
;
1155 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1158 // Initialize the CDB
1161 cdb
= (PCDB
)&srb
->Cdb
[0];
1162 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_TEST_UNIT_READY
;
1163 cdb
->CDB6GENERIC
.LogicalUnitNumber
= deviceExtension
->Lun
;
1166 // It is ok to support media change events on this device.
1169 cddata
->MediaChangeSupported
= TRUE
;
1170 cddata
->MediaChange
= TRUE
;
1184 deviceExtension
->MediaChangeEvent
= NULL
;
1187 deviceExtension
->MediaChangeEvent
= NULL
;
1192 // Assume use of 6-byte mode sense/select for now.
1195 cddata
->XAFlags
|= XA_USE_6_BYTE
;
1198 // Build and issue mode sense with Read error recovery page. This will be used to change
1199 // block size in case of any raw reads (Mode 2, Form 2).
1202 length
= (sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH
);
1204 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
1207 cdb
= (PCDB
)srb
.Cdb
;
1210 // Set timeout value from device extension.
1213 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
1216 // Build the MODE SENSE CDB. The data returned will be kept in the device extension
1217 // and used to set block size.
1220 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
1221 cdb
->MODE_SENSE
.PageCode
= 0x1;
1222 cdb
->MODE_SENSE
.AllocationLength
= (UCHAR
)length
;
1224 buffer
= ExAllocatePool(NonPagedPoolCacheAligned
, (sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH10
));
1226 status
= STATUS_INSUFFICIENT_RESOURCES
;
1227 goto CreateCdRomDeviceObjectExit
;
1230 status
= ScsiClassSendSrbSynchronous(deviceObject
,
1235 if (!NT_SUCCESS(status
)) {
1238 // May be Atapi, try 10-byte.
1241 length
= (sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH10
);
1243 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
1246 // Build the MODE SENSE CDB.
1250 cdb
= (PCDB
)srb
.Cdb
;
1253 // Set timeout value from device extension.
1256 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
1258 cdb
->MODE_SENSE10
.OperationCode
= SCSIOP_MODE_SENSE10
;
1259 cdb
->MODE_SENSE10
.PageCode
= 0x1;
1261 cdb
->MODE_SENSE10
.AllocationLength
[0] = (UCHAR
)(length
>> 8);
1262 cdb
->MODE_SENSE10
.AllocationLength
[1] = (UCHAR
)(length
& 0xFF);
1264 status
= ScsiClassSendSrbSynchronous(deviceObject
,
1269 if (status
== STATUS_DATA_OVERRUN
) {
1272 // Build and issue the ReadCd command to ensure that this device supports it.
1275 RtlZeroMemory(cdb
, 12);
1277 cdb
->READ_CD
.OperationCode
= SCSIOP_READ_CD
;
1279 status
= ScsiClassSendSrbSynchronous(deviceObject
,
1286 // If the command wasn't rejected then support the READ_CD.
1289 if (NT_SUCCESS(status
) || (status
== STATUS_NO_MEDIA_IN_DEVICE
)) {
1292 // Using Read CD precludes issueing a mode select to
1293 // set the user data size. So, no buffer copy is
1297 cddata
->XAFlags
&= ~XA_USE_6_BYTE
;
1298 cddata
->XAFlags
|= XA_USE_READ_CD
| XA_USE_10_BYTE
;
1301 RtlCopyMemory(&cddata
->u1
.Header
, buffer
, sizeof(ERROR_RECOVERY_DATA10
));
1302 cddata
->u1
.Header
.ModeDataLength
= 0;
1304 cddata
->XAFlags
&= ~XA_USE_6_BYTE
;
1305 cddata
->XAFlags
|= XA_USE_10_BYTE
;
1308 } else if (NT_SUCCESS(status
)) {
1310 RtlCopyMemory(&cddata
->u1
.Header
, buffer
, sizeof(ERROR_RECOVERY_DATA10
));
1311 cddata
->u1
.Header
.ModeDataLength
= 0;
1313 cddata
->XAFlags
&= ~XA_USE_6_BYTE
;
1314 cddata
->XAFlags
|= XA_USE_10_BYTE
;
1317 cddata
->XAFlags
|= XA_NOT_SUPPORTED
;
1320 RtlCopyMemory(&cddata
->u1
.Header
, buffer
, sizeof(ERROR_RECOVERY_DATA
));
1321 cddata
->u1
.Header
.ModeDataLength
= 0;
1327 // Start the timer now regardless of if Autorun is enabled.
1328 // The timer must run forever since IoStopTimer faults.
1331 IoInitializeTimer(deviceObject
, CdRomTickHandler
, NULL
);
1332 IoStartTimer(deviceObject
);
1334 return(STATUS_SUCCESS
);
1336 CreateCdRomDeviceObjectExit
:
1339 // Release the device since an error occured.
1342 ScsiClassClaimDevice(PortDeviceObject
,
1347 if (senseData
!= NULL
) {
1348 ExFreePool(senseData
);
1351 if (deviceExtension
->DiskGeometry
!= NULL
) {
1352 ExFreePool(deviceExtension
->DiskGeometry
);
1355 if (deviceObject
!= NULL
) {
1356 if (srbListInitialized
) {
1357 ExDeleteNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
);
1359 IoDeleteDevice(deviceObject
);
1365 } // end CreateCdRomDeviceObject()
1370 IN PDEVICE_OBJECT DeviceObject
,
1375 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1376 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1377 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
1378 PIO_STACK_LOCATION irpStack
;
1380 ULONG transferPages
;
1381 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
1382 ULONG maximumTransferLength
= deviceExtension
->PortCapabilities
->MaximumTransferLength
;
1384 PSCSI_REQUEST_BLOCK srb
= NULL
;
1386 PUCHAR senseBuffer
= NULL
;
1392 // Mark IRP with status pending.
1395 IoMarkIrpPending(Irp
);
1398 // If the flag is set in the device object, force a verify.
1401 if (DeviceObject
->Flags
& DO_VERIFY_VOLUME
) {
1402 DebugPrint((2, "ScsiCdRomStartIo: [%lx] Volume needs verified\n", Irp
));
1403 if (!(currentIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
)) {
1405 if (Irp
->Tail
.Overlay
.Thread
) {
1406 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
1409 Irp
->IoStatus
.Status
= STATUS_VERIFY_REQUIRED
;
1411 DebugPrint((2, "ScsiCdRomStartIo: [%lx] Calling UpdateCapcity - "
1412 "ioctl event = %lx\n",
1414 nextIrpStack
->Parameters
.Others
.Argument1
1418 // our device control dispatch routine stores an event in the next
1419 // stack location to signal when startio has completed. We need to
1420 // pass this in so that the update capacity completion routine can
1421 // set it rather than completing the Irp.
1424 status
= CdRomUpdateCapacity(deviceExtension
,
1426 nextIrpStack
->Parameters
.Others
.Argument1
1429 DebugPrint((2, "ScsiCdRomStartIo: [%lx] UpdateCapacity returned %lx\n", Irp
, status
));
1430 ASSERT(status
== STATUS_PENDING
);
1435 cdData
= (PCDROM_DATA
)(deviceExtension
+ 1);
1436 use6Byte
= cdData
->XAFlags
& XA_USE_6_BYTE
;
1438 if (currentIrpStack
->MajorFunction
== IRP_MJ_READ
) {
1441 // Add partition byte offset to make starting byte relative to
1442 // beginning of disk. In addition, add in skew for DM Driver, if any.
1445 currentIrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+= (deviceExtension
->StartingOffset
.QuadPart
);
1448 // Calculate number of pages in this transfer.
1451 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp
->MdlAddress
),
1452 currentIrpStack
->Parameters
.Read
.Length
);
1455 // Check if request length is greater than the maximum number of
1456 // bytes that the hardware can transfer.
1459 if (cdData
->RawAccess
) {
1461 ASSERT(!(cdData
->XAFlags
& XA_USE_READ_CD
));
1464 // Fire off a mode select to switch back to cooked sectors.
1467 irp2
= IoAllocateIrp((CCHAR
)(deviceExtension
->DeviceObject
->StackSize
+1),
1471 Irp
->IoStatus
.Information
= 0;
1472 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1473 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1474 IoStartNextPacket(DeviceObject
, FALSE
);
1478 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
1480 Irp
->IoStatus
.Information
= 0;
1481 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1482 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1484 IoStartNextPacket(DeviceObject
, FALSE
);
1488 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
1490 cdb
= (PCDB
)srb
->Cdb
;
1493 // Allocate sense buffer.
1496 senseBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
1499 Irp
->IoStatus
.Information
= 0;
1500 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1501 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1504 IoStartNextPacket(DeviceObject
, FALSE
);
1512 IoSetNextIrpStackLocation(irp2
);
1513 irp2
->IoStatus
.Status
= STATUS_SUCCESS
;
1514 irp2
->IoStatus
.Information
= 0;
1516 irp2
->UserBuffer
= NULL
;
1519 // Save the device object and irp in a private stack location.
1522 irpStack
= IoGetCurrentIrpStackLocation(irp2
);
1523 irpStack
->DeviceObject
= deviceExtension
->DeviceObject
;
1524 irpStack
->Parameters
.Others
.Argument2
= (PVOID
) Irp
;
1527 // The retry count will be in the real Irp, as the retry logic will
1528 // recreate our private irp.
1531 if (!(nextIrpStack
->Parameters
.Others
.Argument1
)) {
1534 // Only jam this in if it doesn't exist. The completion routines can
1535 // call StartIo directly in the case of retries and resetting it will
1536 // cause infinite loops.
1539 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
1543 // Construct the IRP stack for the lower level driver.
1546 irpStack
= IoGetNextIrpStackLocation(irp2
);
1547 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
1548 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
1549 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1551 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1552 srb
->PathId
= deviceExtension
->PathId
;
1553 srb
->TargetId
= deviceExtension
->TargetId
;
1554 srb
->Lun
= deviceExtension
->Lun
;
1555 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1556 srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
1557 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
1559 srb
->OriginalRequest
= irp2
;
1560 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1561 srb
->SenseInfoBuffer
= senseBuffer
;
1563 transferByteCount
= (use6Byte
) ? sizeof(ERROR_RECOVERY_DATA
) : sizeof(ERROR_RECOVERY_DATA10
);
1564 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, transferByteCount
);
1566 Irp
->IoStatus
.Information
= 0;
1567 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1568 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1569 ExFreePool(senseBuffer
);
1572 IoStartNextPacket(DeviceObject
, FALSE
);
1577 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
1583 if (!irp2
->MdlAddress
) {
1584 Irp
->IoStatus
.Information
= 0;
1585 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1586 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1587 ExFreePool(senseBuffer
);
1589 ExFreePool(dataBuffer
);
1591 IoStartNextPacket(DeviceObject
, FALSE
);
1599 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
1601 srb
->DataBuffer
= dataBuffer
;
1604 // Set the new block size in the descriptor.
1607 cdData
->u1
.BlockDescriptor
.BlockLength
[0] = (UCHAR
)(COOKED_SECTOR_SIZE
>> 16) & 0xFF;
1608 cdData
->u1
.BlockDescriptor
.BlockLength
[1] = (UCHAR
)(COOKED_SECTOR_SIZE
>> 8) & 0xFF;
1609 cdData
->u1
.BlockDescriptor
.BlockLength
[2] = (UCHAR
)(COOKED_SECTOR_SIZE
& 0xFF);
1612 // Move error page into dataBuffer.
1615 RtlCopyMemory(srb
->DataBuffer
, &cdData
->u1
.Header
, transferByteCount
);
1618 // Build and send a mode select to switch into raw mode.
1621 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
1622 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_OUT
);
1623 srb
->DataTransferLength
= transferByteCount
;
1624 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
* 2;
1628 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
1629 cdb
->MODE_SELECT
.PFBit
= 1;
1630 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)transferByteCount
;
1633 srb
->CdbLength
= 10;
1634 cdb
->MODE_SELECT10
.OperationCode
= SCSIOP_MODE_SELECT10
;
1635 cdb
->MODE_SELECT10
.PFBit
= 1;
1636 cdb
->MODE_SELECT10
.ParameterListLength
[0] = (UCHAR
)(transferByteCount
>> 8);
1637 cdb
->MODE_SELECT10
.ParameterListLength
[1] = (UCHAR
)(transferByteCount
& 0xFF);
1641 // Update completion routine.
1644 IoSetCompletionRoutine(irp2
,
1645 CdRomSwitchModeCompletion
,
1651 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
1655 if ((currentIrpStack
->Parameters
.Read
.Length
> maximumTransferLength
) ||
1657 deviceExtension
->PortCapabilities
->MaximumPhysicalPages
)) {
1660 // Request needs to be split. Completion of each portion of the
1661 // request will fire off the next portion. The final request will
1662 // signal Io to send a new request.
1666 deviceExtension
->PortCapabilities
->MaximumPhysicalPages
- 1;
1668 if(maximumTransferLength
> transferPages
<< PAGE_SHIFT
) {
1669 maximumTransferLength
= transferPages
<< PAGE_SHIFT
;
1673 // Check that the maximum transfer size is not zero
1676 if(maximumTransferLength
== 0) {
1677 maximumTransferLength
= PAGE_SIZE
;
1680 ScsiClassSplitRequest(DeviceObject
, Irp
, maximumTransferLength
);
1686 // Build SRB and CDB for this IRP.
1689 ScsiClassBuildRequest(DeviceObject
, Irp
);
1694 } else if (currentIrpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
) {
1697 // Allocate an irp, srb and associated structures.
1700 irp2
= IoAllocateIrp((CCHAR
)(deviceExtension
->DeviceObject
->StackSize
+1),
1704 Irp
->IoStatus
.Information
= 0;
1705 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1706 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1707 IoStartNextPacket(DeviceObject
, FALSE
);
1708 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp
, Irp
->IoStatus
.Status
, __LINE__
));
1712 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
1714 Irp
->IoStatus
.Information
= 0;
1715 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1716 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1718 IoStartNextPacket(DeviceObject
, FALSE
);
1719 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp
, Irp
->IoStatus
.Status
, __LINE__
));
1723 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
1725 cdb
= (PCDB
)srb
->Cdb
;
1728 // Allocate sense buffer.
1731 senseBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
1734 Irp
->IoStatus
.Information
= 0;
1735 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1736 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1739 IoStartNextPacket(DeviceObject
, FALSE
);
1740 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp
, Irp
->IoStatus
.Status
, __LINE__
));
1748 IoSetNextIrpStackLocation(irp2
);
1749 irp2
->IoStatus
.Status
= STATUS_SUCCESS
;
1750 irp2
->IoStatus
.Information
= 0;
1752 irp2
->UserBuffer
= NULL
;
1755 // Save the device object and irp in a private stack location.
1758 irpStack
= IoGetCurrentIrpStackLocation(irp2
);
1759 irpStack
->DeviceObject
= deviceExtension
->DeviceObject
;
1760 irpStack
->Parameters
.Others
.Argument2
= (PVOID
) Irp
;
1763 // The retry count will be in the real Irp, as the retry logic will
1764 // recreate our private irp.
1767 if (!(nextIrpStack
->Parameters
.Others
.Argument1
)) {
1770 // Only jam this in if it doesn't exist. The completion routines can
1771 // call StartIo directly in the case of retries and resetting it will
1772 // cause infinite loops.
1775 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
1779 // Construct the IRP stack for the lower level driver.
1782 irpStack
= IoGetNextIrpStackLocation(irp2
);
1783 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
1784 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
1785 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1787 IoSetCompletionRoutine(irp2
,
1788 CdRomDeviceControlCompletion
,
1794 // Setup those fields that are generic to all requests.
1797 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1798 srb
->PathId
= deviceExtension
->PathId
;
1799 srb
->TargetId
= deviceExtension
->TargetId
;
1800 srb
->Lun
= deviceExtension
->Lun
;
1801 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1802 srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
1803 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
1805 srb
->OriginalRequest
= irp2
;
1806 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1807 srb
->SenseInfoBuffer
= senseBuffer
;
1809 switch (currentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
) {
1811 case IOCTL_CDROM_RAW_READ
: {
1814 // Determine whether the drive is currently in raw or cooked mode,
1815 // and which command to use to read the data.
1818 if (!(cdData
->XAFlags
& XA_USE_READ_CD
)) {
1820 PRAW_READ_INFO rawReadInfo
=
1821 (PRAW_READ_INFO
)currentIrpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
1822 ULONG maximumTransferLength
;
1823 ULONG transferPages
;
1825 if (cdData
->RawAccess
) {
1827 ULONG startingSector
;
1830 // Free the recently allocated irp, as we don't need it.
1835 cdb
= (PCDB
)srb
->Cdb
;
1836 RtlZeroMemory(cdb
, 12);
1839 // Calculate starting offset.
1842 startingSector
= (ULONG
)(rawReadInfo
->DiskOffset
.QuadPart
>> deviceExtension
->SectorShift
);
1843 transferByteCount
= rawReadInfo
->SectorCount
* RAW_SECTOR_SIZE
;
1844 maximumTransferLength
= deviceExtension
->PortCapabilities
->MaximumTransferLength
;
1845 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp
->MdlAddress
),
1849 // Determine if request is within limits imposed by miniport.
1852 if (transferByteCount
> maximumTransferLength
||
1853 transferPages
> deviceExtension
->PortCapabilities
->MaximumPhysicalPages
) {
1856 // The claim is that this won't happen, and is backed up by
1857 // ActiveMovie usage, which does unbuffered XA reads of 0x18000, yet
1858 // we get only 4 sector requests.
1862 Irp
->IoStatus
.Information
= 0;
1863 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
1864 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1865 ExFreePool(senseBuffer
);
1867 IoStartNextPacket(DeviceObject
, FALSE
);
1872 srb
->OriginalRequest
= Irp
;
1873 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
1874 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
1875 srb
->DataTransferLength
= transferByteCount
;
1876 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
1877 srb
->CdbLength
= 10;
1878 srb
->DataBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
1880 if (rawReadInfo
->TrackMode
== CDDA
) {
1881 if (cdData
->XAFlags
& PLEXTOR_CDDA
) {
1883 srb
->CdbLength
= 12;
1885 cdb
->PLXTR_READ_CDDA
.LogicalUnitNumber
= deviceExtension
->Lun
;
1886 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
1887 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
1888 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
1889 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
1891 cdb
->PLXTR_READ_CDDA
.TransferBlockByte3
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
1892 cdb
->PLXTR_READ_CDDA
.TransferBlockByte2
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
1893 cdb
->PLXTR_READ_CDDA
.TransferBlockByte1
= 0;
1894 cdb
->PLXTR_READ_CDDA
.TransferBlockByte0
= 0;
1896 cdb
->PLXTR_READ_CDDA
.SubCode
= 0;
1897 cdb
->PLXTR_READ_CDDA
.OperationCode
= 0xD8;
1899 } else if (cdData
->XAFlags
& NEC_CDDA
) {
1901 cdb
->NEC_READ_CDDA
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
1902 cdb
->NEC_READ_CDDA
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
1903 cdb
->NEC_READ_CDDA
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
1904 cdb
->NEC_READ_CDDA
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
1906 cdb
->NEC_READ_CDDA
.TransferBlockByte1
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
1907 cdb
->NEC_READ_CDDA
.TransferBlockByte0
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
1909 cdb
->NEC_READ_CDDA
.OperationCode
= 0xD4;
1913 cdb
->CDB10
.LogicalUnitNumber
= deviceExtension
->Lun
;
1915 cdb
->CDB10
.TransferBlocksMsb
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
1916 cdb
->CDB10
.TransferBlocksLsb
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
1918 cdb
->CDB10
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
1919 cdb
->CDB10
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
1920 cdb
->CDB10
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
1921 cdb
->CDB10
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
1923 cdb
->CDB10
.OperationCode
= SCSIOP_READ
;
1926 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
1928 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
1929 nextIrpStack
->Parameters
.Scsi
.Srb
= srb
;
1931 if (!(nextIrpStack
->Parameters
.Others
.Argument1
)) {
1934 // Only jam this in if it doesn't exist. The completion routines can
1935 // call StartIo directly in the case of retries and resetting it will
1936 // cause infinite loops.
1939 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
1943 // Set up IoCompletion routine address.
1946 IoSetCompletionRoutine(Irp
,
1953 IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
1958 transferByteCount
= (use6Byte
) ? sizeof(ERROR_RECOVERY_DATA
) : sizeof(ERROR_RECOVERY_DATA10
);
1959 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, transferByteCount
);
1961 Irp
->IoStatus
.Information
= 0;
1962 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1963 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1964 ExFreePool(senseBuffer
);
1967 IoStartNextPacket(DeviceObject
, FALSE
);
1972 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
1978 if (!irp2
->MdlAddress
) {
1979 Irp
->IoStatus
.Information
= 0;
1980 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1981 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1982 ExFreePool(senseBuffer
);
1984 ExFreePool(dataBuffer
);
1986 IoStartNextPacket(DeviceObject
, FALSE
);
1994 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
1996 srb
->DataBuffer
= dataBuffer
;
1999 // Set the new block size in the descriptor.
2002 cdData
->u1
.BlockDescriptor
.BlockLength
[0] = (UCHAR
)(RAW_SECTOR_SIZE
>> 16) & 0xFF;
2003 cdData
->u1
.BlockDescriptor
.BlockLength
[1] = (UCHAR
)(RAW_SECTOR_SIZE
>> 8) & 0xFF;
2004 cdData
->u1
.BlockDescriptor
.BlockLength
[2] = (UCHAR
)(RAW_SECTOR_SIZE
& 0xFF);
2008 // TODO: Set density code, based on operation
2011 cdData
->u1
.BlockDescriptor
.DensityCode
= 0;
2015 // Move error page into dataBuffer.
2018 RtlCopyMemory(srb
->DataBuffer
, &cdData
->u1
.Header
, transferByteCount
);
2022 // Build and send a mode select to switch into raw mode.
2025 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2026 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_OUT
);
2027 srb
->DataTransferLength
= transferByteCount
;
2028 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
* 2;
2032 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
2033 cdb
->MODE_SELECT
.PFBit
= 1;
2034 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)transferByteCount
;
2037 srb
->CdbLength
= 10;
2038 cdb
->MODE_SELECT10
.OperationCode
= SCSIOP_MODE_SELECT10
;
2039 cdb
->MODE_SELECT10
.PFBit
= 1;
2040 cdb
->MODE_SELECT10
.ParameterListLength
[0] = (UCHAR
)(transferByteCount
>> 8);
2041 cdb
->MODE_SELECT10
.ParameterListLength
[1] = (UCHAR
)(transferByteCount
& 0xFF);
2045 // Update completion routine.
2048 IoSetCompletionRoutine(irp2
,
2049 CdRomSwitchModeCompletion
,
2059 PRAW_READ_INFO rawReadInfo
=
2060 (PRAW_READ_INFO
)currentIrpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
2061 ULONG startingSector
;
2064 // Free the recently allocated irp, as we don't need it.
2069 cdb
= (PCDB
)srb
->Cdb
;
2070 RtlZeroMemory(cdb
, 12);
2074 // Calculate starting offset.
2077 startingSector
= (ULONG
)(rawReadInfo
->DiskOffset
.QuadPart
>> deviceExtension
->SectorShift
);
2078 transferByteCount
= rawReadInfo
->SectorCount
* RAW_SECTOR_SIZE
;
2081 srb
->OriginalRequest
= Irp
;
2082 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2083 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
2084 srb
->DataTransferLength
= transferByteCount
;
2085 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2086 srb
->DataBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
2087 srb
->CdbLength
= 12;
2088 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
2091 // Fill in CDB fields.
2094 cdb
= (PCDB
)srb
->Cdb
;
2097 cdb
->READ_CD
.TransferBlocks
[2] = (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
2098 cdb
->READ_CD
.TransferBlocks
[1] = (UCHAR
) (rawReadInfo
->SectorCount
>> 8 );
2099 cdb
->READ_CD
.TransferBlocks
[0] = (UCHAR
) (rawReadInfo
->SectorCount
>> 16);
2102 cdb
->READ_CD
.StartingLBA
[3] = (UCHAR
) (startingSector
& 0xFF);
2103 cdb
->READ_CD
.StartingLBA
[2] = (UCHAR
) ((startingSector
>> 8));
2104 cdb
->READ_CD
.StartingLBA
[1] = (UCHAR
) ((startingSector
>> 16));
2105 cdb
->READ_CD
.StartingLBA
[0] = (UCHAR
) ((startingSector
>> 24));
2108 // Setup cdb depending upon the sector type we want.
2111 switch (rawReadInfo
->TrackMode
) {
2114 cdb
->READ_CD
.ExpectedSectorType
= CD_DA_SECTOR
;
2115 cdb
->READ_CD
.IncludeUserData
= 1;
2116 cdb
->READ_CD
.HeaderCode
= 3;
2117 cdb
->READ_CD
.IncludeSyncData
= 1;
2122 cdb
->READ_CD
.ExpectedSectorType
= YELLOW_MODE2_SECTOR
;
2123 cdb
->READ_CD
.IncludeUserData
= 1;
2124 cdb
->READ_CD
.HeaderCode
= 1;
2125 cdb
->READ_CD
.IncludeSyncData
= 1;
2130 cdb
->READ_CD
.ExpectedSectorType
= FORM2_MODE2_SECTOR
;
2131 cdb
->READ_CD
.IncludeUserData
= 1;
2132 cdb
->READ_CD
.HeaderCode
= 3;
2133 cdb
->READ_CD
.IncludeSyncData
= 1;
2137 Irp
->IoStatus
.Information
= 0;
2138 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
2139 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2140 ExFreePool(senseBuffer
);
2142 IoStartNextPacket(DeviceObject
, FALSE
);
2143 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp
, Irp
->IoStatus
.Status
, __LINE__
));
2147 cdb
->READ_CD
.OperationCode
= SCSIOP_READ_CD
;
2149 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
2150 nextIrpStack
->Parameters
.Scsi
.Srb
= srb
;
2152 if (!(nextIrpStack
->Parameters
.Others
.Argument1
)) {
2155 // Only jam this in if it doesn't exist. The completion routines can
2156 // call StartIo directly in the case of retries and resetting it will
2157 // cause infinite loops.
2160 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
2164 // Set up IoCompletion routine address.
2167 IoSetCompletionRoutine(Irp
,
2174 IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
2179 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2183 case IOCTL_DISK_GET_LENGTH_INFO
:
2184 case IOCTL_DISK_GET_DRIVE_GEOMETRY_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 informatin 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_CDROM_GET_DRIVE_GEOMETRY
: {
4732 DebugPrint((2,"CdRomDeviceControl: Get drive geometry\n"));
4734 if ( irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
4735 sizeof( DISK_GEOMETRY
) ) {
4737 status
= STATUS_INFO_LENGTH_MISMATCH
;
4741 IoMarkIrpPending(Irp
);
4742 IoStartPacket(DeviceObject
,Irp
, NULL
,NULL
);
4744 return STATUS_PENDING
;
4747 case IOCTL_CDROM_GET_LAST_SESSION
:
4748 case IOCTL_CDROM_READ_TOC
: {
4751 // If the cd is playing music then reject this request.
4754 if (CdRomIsPlayActive(DeviceObject
)) {
4755 Irp
->IoStatus
.Status
= STATUS_DEVICE_BUSY
;
4756 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4757 return STATUS_DEVICE_BUSY
;
4760 IoMarkIrpPending(Irp
);
4761 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4763 return STATUS_PENDING
;
4766 case IOCTL_CDROM_PLAY_AUDIO_MSF
: {
4772 DebugPrint((2,"CdRomDeviceControl: Play audio MSF\n"));
4774 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
4775 sizeof(CDROM_PLAY_AUDIO_MSF
)) {
4778 // Indicate unsuccessful status.
4781 status
= STATUS_BUFFER_TOO_SMALL
;
4785 IoMarkIrpPending(Irp
);
4786 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4788 return STATUS_PENDING
;
4791 case IOCTL_CDROM_SEEK_AUDIO_MSF
: {
4798 DebugPrint((2,"CdRomDeviceControl: Seek audio MSF\n"));
4800 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
4801 sizeof(CDROM_SEEK_AUDIO_MSF
)) {
4804 // Indicate unsuccessful status.
4807 status
= STATUS_BUFFER_TOO_SMALL
;
4810 IoMarkIrpPending(Irp
);
4811 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4813 return STATUS_PENDING
;
4818 case IOCTL_CDROM_PAUSE_AUDIO
: {
4824 DebugPrint((2, "CdRomDeviceControl: Pause audio\n"));
4826 IoMarkIrpPending(Irp
);
4827 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4829 return STATUS_PENDING
;
4834 case IOCTL_CDROM_RESUME_AUDIO
: {
4840 DebugPrint((2, "CdRomDeviceControl: Resume audio\n"));
4842 IoMarkIrpPending(Irp
);
4843 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4845 return STATUS_PENDING
;
4848 case IOCTL_CDROM_READ_Q_CHANNEL
: {
4850 if(irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
4851 sizeof(CDROM_SUB_Q_DATA_FORMAT
)) {
4853 status
= STATUS_BUFFER_TOO_SMALL
;
4854 Irp
->IoStatus
.Information
= 0;
4858 IoMarkIrpPending(Irp
);
4859 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4861 return STATUS_PENDING
;
4864 case IOCTL_CDROM_GET_CONTROL
: {
4866 DebugPrint((2, "CdRomDeviceControl: Get audio control\n"));
4869 // Verify user buffer is large enough for the data.
4872 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
4873 sizeof(CDROM_AUDIO_CONTROL
)) {
4876 // Indicate unsuccessful status and no data transferred.
4879 status
= STATUS_BUFFER_TOO_SMALL
;
4880 Irp
->IoStatus
.Information
= 0;
4885 IoMarkIrpPending(Irp
);
4886 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4888 return STATUS_PENDING
;
4892 case IOCTL_CDROM_GET_VOLUME
: {
4894 DebugPrint((2, "CdRomDeviceControl: Get volume control\n"));
4897 // Verify user buffer is large enough for data.
4900 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
4901 sizeof(VOLUME_CONTROL
)) {
4904 // Indicate unsuccessful status and no data transferred.
4907 status
= STATUS_BUFFER_TOO_SMALL
;
4908 Irp
->IoStatus
.Information
= 0;
4912 IoMarkIrpPending(Irp
);
4913 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4915 return STATUS_PENDING
;
4919 case IOCTL_CDROM_SET_VOLUME
: {
4921 DebugPrint((2, "CdRomDeviceControl: Set volume control\n"));
4923 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
4924 sizeof(VOLUME_CONTROL
)) {
4927 // Indicate unsuccessful status.
4930 status
= STATUS_BUFFER_TOO_SMALL
;
4934 IoMarkIrpPending(Irp
);
4935 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4937 return STATUS_PENDING
;
4941 case IOCTL_CDROM_STOP_AUDIO
: {
4947 DebugPrint((2, "CdRomDeviceControl: Stop audio\n"));
4949 IoMarkIrpPending(Irp
);
4950 IoStartPacket(DeviceObject
,Irp
, NULL
,NULL
);
4952 return STATUS_PENDING
;
4955 case IOCTL_CDROM_CHECK_VERIFY
: {
4956 DebugPrint((1, "CdRomDeviceControl: [%lx] Check Verify\n", Irp
));
4957 IoMarkIrpPending(Irp
);
4959 if((irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
) &&
4960 (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))) {
4962 DebugPrint((1, "CdRomDeviceControl: Check Verify: media count "
4963 "buffer too small\n"));
4965 status
= STATUS_BUFFER_TOO_SMALL
;
4969 IoStartPacket(DeviceObject
,Irp
, NULL
,NULL
);
4971 return STATUS_PENDING
;
4977 // allocate an event and stuff it into our stack location.
4980 deviceControlEvent
= ExAllocatePool(NonPagedPool
, sizeof(KEVENT
));
4982 if(!deviceControlEvent
) {
4984 status
= STATUS_INSUFFICIENT_RESOURCES
;
4988 PIO_STACK_LOCATION currentStack
;
4990 KeInitializeEvent(deviceControlEvent
, NotificationEvent
, FALSE
);
4992 currentStack
= IoGetCurrentIrpStackLocation(Irp
);
4993 nextStack
= IoGetNextIrpStackLocation(Irp
);
4996 // Copy the stack down a notch
4999 *nextStack
= *currentStack
;
5001 IoSetCompletionRoutine(
5003 CdRomClassIoctlCompletion
,
5010 IoSetNextIrpStackLocation(Irp
);
5012 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
5013 Irp
->IoStatus
.Information
= 0;
5016 // Override volume verifies on this stack location so that we
5017 // will be forced through the synchronization. Once this location
5018 // goes away we get the old value back
5021 nextStack
->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
5023 IoMarkIrpPending(Irp
);
5025 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
5028 // Wait for CdRomClassIoctlCompletion to set the event. This
5029 // ensures serialization remains intact for these unhandled device
5033 KeWaitForSingleObject(
5040 ExFreePool(deviceControlEvent
);
5042 DebugPrint((2, "CdRomDeviceControl: irp %#08lx synchronized\n", Irp
));
5045 // If an error occured then propagate that back up - we are no longer
5046 // guaranteed synchronization and the upper layers will have to
5049 // If no error occured, call down to the class driver directly
5050 // then start up the next request.
5053 if(Irp
->IoStatus
.Status
== STATUS_SUCCESS
) {
5055 status
= ScsiClassDeviceControl(DeviceObject
, Irp
);
5057 KeRaiseIrql(DISPATCH_LEVEL
, &irql
);
5059 IoStartNextPacket(DeviceObject
, FALSE
);
5070 if (status
== STATUS_VERIFY_REQUIRED
) {
5073 // If the status is verified required and this request
5074 // should bypass verify required then retry the request.
5077 if (irpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
) {
5079 status
= STATUS_IO_DEVICE_ERROR
;
5085 if (IoIsErrorUserInduced(status
)) {
5087 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
5092 // Update IRP with completion status.
5095 Irp
->IoStatus
.Status
= status
;
5098 // Complete the request.
5101 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
5102 DebugPrint((2, "CdRomDeviceControl: Status is %lx\n", status
));
5105 } // end ScsiCdRomDeviceControl()
5110 PDEVICE_OBJECT DeviceObject
,
5111 PINQUIRYDATA InquiryData
,
5112 PIO_SCSI_CAPABILITIES PortCapabilities
5117 Routine Description:
5119 This function checks to see if an SCSI logical unit requires an special
5120 initialization or error processing.
5124 DeviceObject - Supplies the device object to be tested.
5126 InquiryData - Supplies the inquiry data returned by the device of interest.
5128 PortCapabilities - Supplies the capabilities of the device object.
5137 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
5138 PCDROM_DATA cdData
= (PCDROM_DATA
)(deviceExtension
+1);
5141 // Look for a Hitachi CDR-1750. Read-ahead must be disabled in order
5142 // to get this cdrom drive to work on scsi adapters that use PIO.
5145 if ((strncmp((PCHAR
)InquiryData
->VendorId
, "HITACHI CDR-1750S", strlen("HITACHI CDR-1750S")) == 0 ||
5146 strncmp((PCHAR
)InquiryData
->VendorId
, "HITACHI CDR-3650/1650S", strlen("HITACHI CDR-3650/1650S")) == 0)
5147 && PortCapabilities
->AdapterUsesPio
) {
5149 DebugPrint((1, "CdRom ScanForSpecial: Found Hitachi CDR-1750S.\n"));
5152 // Setup an error handler to reinitialize the cd rom after it is reset.
5155 deviceExtension
->ClassError
= HitachProcessError
;
5157 } else if (( RtlCompareMemory( InquiryData
->VendorId
,"FUJITSU", 7 ) == 7 ) &&
5158 (( RtlCompareMemory( InquiryData
->ProductId
,"FMCD-101", 8 ) == 8 ) ||
5159 ( RtlCompareMemory( InquiryData
->ProductId
,"FMCD-102", 8 ) == 8 ))) {
5162 // When Read command is issued to FMCD-101 or FMCD-102 and there is a music
5163 // cd in it. It takes longer time than SCSI_CDROM_TIMEOUT before returning
5167 deviceExtension
->TimeOutValue
= 20;
5169 } else if (( RtlCompareMemory( InquiryData
->VendorId
,"TOSHIBA", 7) == 7) &&
5170 (( RtlCompareMemory( InquiryData
->ProductId
,"CD-ROM XM-34", 12) == 12))) {
5172 SCSI_REQUEST_BLOCK srb
;
5179 // Set the density code and the error handler.
5182 length
= (sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH
);
5184 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
5187 // Build the MODE SENSE CDB.
5191 cdb
= (PCDB
)srb
.Cdb
;
5194 // Set timeout value from device extension.
5197 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
5199 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
5200 cdb
->MODE_SENSE
.PageCode
= 0x1;
5201 cdb
->MODE_SENSE
.AllocationLength
= (UCHAR
)length
;
5203 buffer
= ExAllocatePool(NonPagedPoolCacheAligned
, (sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH
));
5208 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
5214 ((PERROR_RECOVERY_DATA
)buffer
)->BlockDescriptor
.DensityCode
= 0x83;
5215 ((PERROR_RECOVERY_DATA
)buffer
)->Header
.ModeDataLength
= 0x0;
5217 RtlCopyMemory(&cdData
->u1
.Header
, buffer
, sizeof(ERROR_RECOVERY_DATA
));
5219 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
5222 // Build the MODE SENSE CDB.
5226 cdb
= (PCDB
)srb
.Cdb
;
5229 // Set timeout value from device extension.
5232 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
5234 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
5235 cdb
->MODE_SELECT
.PFBit
= 1;
5236 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)length
;
5238 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
5244 if (!NT_SUCCESS(status
)) {
5246 "Cdrom.ScanForSpecial: Setting density code on Toshiba failed [%x]\n",
5250 deviceExtension
->ClassError
= ToshibaProcessError
;
5257 // Determine special CD-DA requirements.
5260 if (RtlCompareMemory( InquiryData
->VendorId
,"PLEXTOR",7) == 7) {
5261 cdData
->XAFlags
|= PLEXTOR_CDDA
;
5262 } else if (RtlCompareMemory ( InquiryData
->VendorId
,"NEC",3) == 3) {
5263 cdData
->XAFlags
|= NEC_CDDA
;
5272 PDEVICE_OBJECT DeviceObject
,
5273 PSCSI_REQUEST_BLOCK Srb
,
5279 Routine Description:
5281 This routine checks the type of error. If the error indicates CD-ROM the
5282 CD-ROM needs to be reinitialized then a Mode sense command is sent to the
5283 device. This command disables read-ahead for the device.
5287 DeviceObject - Supplies a pointer to the device object.
5289 Srb - Supplies a pointer to the failing Srb.
5302 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
5303 PSENSE_DATA senseBuffer
= Srb
->SenseInfoBuffer
;
5304 LARGE_INTEGER largeInt
;
5306 PIO_STACK_LOCATION irpStack
;
5308 PSCSI_REQUEST_BLOCK srb
;
5309 PCOMPLETION_CONTEXT context
;
5313 UNREFERENCED_PARAMETER(Status
);
5314 UNREFERENCED_PARAMETER(Retry
);
5316 largeInt
.QuadPart
= (LONGLONG
) 1;
5319 // Check the status. The initialization command only needs to be sent
5320 // if UNIT ATTENTION is returned.
5323 if (!(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
)) {
5326 // The drive does not require reinitialization.
5333 // Found a bad HITACHI cd-rom. These devices do not work with PIO
5334 // adapters when read-ahead is enabled. Read-ahead is disabled by
5335 // a mode select command. The mode select page code is zero and the
5336 // length is 6 bytes. All of the other bytes should be zero.
5340 if ((senseBuffer
->SenseKey
& 0xf) == SCSI_SENSE_UNIT_ATTENTION
) {
5342 DebugPrint((1, "HitachiProcessError: Reinitializing the CD-ROM.\n"));
5345 // Send the special mode select command to disable read-ahead
5346 // on the CD-ROM reader.
5349 alignment
= DeviceObject
->AlignmentRequirement
?
5350 DeviceObject
->AlignmentRequirement
: 1;
5352 context
= ExAllocatePool(
5354 sizeof(COMPLETION_CONTEXT
) + HITACHI_MODE_DATA_SIZE
+ alignment
5357 if (context
== NULL
) {
5360 // If there is not enough memory to fulfill this request,
5361 // simply return. A subsequent retry will fail and another
5362 // chance to start the unit.
5368 context
->DeviceObject
= DeviceObject
;
5369 srb
= &context
->Srb
;
5371 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
5374 // Write length to SRB.
5377 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
5380 // Set up SCSI bus address.
5383 srb
->PathId
= deviceExtension
->PathId
;
5384 srb
->TargetId
= deviceExtension
->TargetId
;
5385 srb
->Lun
= deviceExtension
->Lun
;
5387 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
5388 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
5391 // Set the transfer length.
5394 srb
->DataTransferLength
= HITACHI_MODE_DATA_SIZE
;
5395 srb
->SrbFlags
= SRB_FLAGS_DATA_OUT
| SRB_FLAGS_DISABLE_AUTOSENSE
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
5398 // The data buffer must be aligned.
5401 srb
->DataBuffer
= (PVOID
) (((ULONG_PTR
) (context
+ 1) + (alignment
- 1)) &
5406 // Build the HITACHI read-ahead mode select CDB.
5410 cdb
= (PCDB
)srb
->Cdb
;
5411 cdb
->MODE_SENSE
.LogicalUnitNumber
= srb
->Lun
;
5412 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SELECT
;
5413 cdb
->MODE_SENSE
.AllocationLength
= HITACHI_MODE_DATA_SIZE
;
5416 // Initialize the mode sense data.
5419 modePage
= srb
->DataBuffer
;
5421 RtlZeroMemory(modePage
, HITACHI_MODE_DATA_SIZE
);
5424 // Set the page length field to 6.
5430 // Build the asynchronous request to be sent to the port driver.
5433 irp
= IoBuildAsynchronousFsdRequest(IRP_MJ_WRITE
,
5436 srb
->DataTransferLength
,
5440 IoSetCompletionRoutine(irp
,
5441 (PIO_COMPLETION_ROUTINE
)ScsiClassAsynchronousCompletion
,
5447 irpStack
= IoGetNextIrpStackLocation(irp
);
5449 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
5451 srb
->OriginalRequest
= irp
;
5454 // Save SRB address in next stack for port driver.
5457 irpStack
->Parameters
.Scsi
.Srb
= (PVOID
)srb
;
5460 // Set up IRP Address.
5463 (VOID
)IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
5470 ToshibaProcessErrorCompletion(
5471 PDEVICE_OBJECT DeviceObject
,
5478 Routine Description:
5480 Completion routine for the ClassError routine to handle older Toshiba units
5481 that require setting the density code.
5485 DeviceObject - Supplies a pointer to the device object.
5487 Irp - Pointer to irp created to set the density code.
5489 Context - Supplies a pointer to the Mode Select Srb.
5494 STATUS_MORE_PROCESSING_REQUIRED
5500 PSCSI_REQUEST_BLOCK srb
= Context
;
5503 // Check for a frozen queue.
5506 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
5509 // Unfreeze the queue getting the device object from the context.
5512 ScsiClassReleaseQueue(DeviceObject
);
5516 // Free all of the allocations.
5519 ExFreePool(srb
->DataBuffer
);
5521 IoFreeMdl(Irp
->MdlAddress
);
5525 // Indicate the I/O system should stop processing the Irp completion.
5528 return STATUS_MORE_PROCESSING_REQUIRED
;
5533 ToshibaProcessError(
5534 PDEVICE_OBJECT DeviceObject
,
5535 PSCSI_REQUEST_BLOCK Srb
,
5542 Routine Description:
5544 This routine checks the type of error. If the error indicates a unit attention,
5545 the density code needs to be set via a Mode select command.
5549 DeviceObject - Supplies a pointer to the device object.
5551 Srb - Supplies a pointer to the failing Srb.
5564 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
5565 PCDROM_DATA cdData
= (PCDROM_DATA
)(deviceExtension
+1);
5566 PSENSE_DATA senseBuffer
= Srb
->SenseInfoBuffer
;
5567 PIO_STACK_LOCATION irpStack
;
5569 PSCSI_REQUEST_BLOCK srb
;
5575 if (!(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
)) {
5580 // The Toshiba's require the density code to be set on power up and media changes.
5583 if ((senseBuffer
->SenseKey
& 0xf) == SCSI_SENSE_UNIT_ATTENTION
) {
5586 irp
= IoAllocateIrp((CCHAR
)(deviceExtension
->DeviceObject
->StackSize
+1),
5593 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
5600 length
= sizeof(ERROR_RECOVERY_DATA
);
5601 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, length
);
5608 irp
->MdlAddress
= IoAllocateMdl(dataBuffer
,
5614 if (!irp
->MdlAddress
) {
5616 ExFreePool(dataBuffer
);
5625 MmBuildMdlForNonPagedPool(irp
->MdlAddress
);
5627 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
5629 srb
->DataBuffer
= dataBuffer
;
5630 cdb
= (PCDB
)srb
->Cdb
;
5636 IoSetNextIrpStackLocation(irp
);
5637 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
5638 irp
->IoStatus
.Information
= 0;
5640 irp
->UserBuffer
= NULL
;
5643 // Save the device object and irp in a private stack location.
5646 irpStack
= IoGetCurrentIrpStackLocation(irp
);
5647 irpStack
->DeviceObject
= deviceExtension
->DeviceObject
;
5650 // Construct the IRP stack for the lower level driver.
5653 irpStack
= IoGetNextIrpStackLocation(irp
);
5654 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
5655 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_OUT
;
5656 irpStack
->Parameters
.Scsi
.Srb
= srb
;
5658 IoSetCompletionRoutine(irp
,
5659 ToshibaProcessErrorCompletion
,
5665 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
5666 srb
->PathId
= deviceExtension
->PathId
;
5667 srb
->TargetId
= deviceExtension
->TargetId
;
5668 srb
->Lun
= deviceExtension
->Lun
;
5669 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
5670 srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
5671 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
5673 srb
->OriginalRequest
= irp
;
5674 srb
->SenseInfoBufferLength
= 0;
5677 // Set the transfer length.
5680 srb
->DataTransferLength
= length
;
5681 srb
->SrbFlags
= SRB_FLAGS_DATA_OUT
| SRB_FLAGS_DISABLE_AUTOSENSE
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
5685 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
5686 cdb
->MODE_SELECT
.PFBit
= 1;
5687 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)length
;
5690 // Copy the Mode page into the databuffer.
5693 RtlCopyMemory(srb
->DataBuffer
, &cdData
->u1
.Header
, length
);
5696 // Set the density code.
5699 ((PERROR_RECOVERY_DATA
)srb
->DataBuffer
)->BlockDescriptor
.DensityCode
= 0x83;
5701 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
5708 IN PDEVICE_OBJECT DeviceObject
5713 Routine Description:
5715 This routine determines if the cd is currently playing music.
5719 DeviceObject - Device object to test.
5723 TRUE if the device is playing music.
5727 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
5729 IO_STATUS_BLOCK ioStatus
;
5732 PSUB_Q_CURRENT_POSITION currentBuffer
;
5734 if (!PLAY_ACTIVE(deviceExtension
)) {
5738 currentBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, sizeof(SUB_Q_CURRENT_POSITION
));
5740 if (currentBuffer
== NULL
) {
5744 ((PCDROM_SUB_Q_DATA_FORMAT
) currentBuffer
)->Format
= IOCTL_CDROM_CURRENT_POSITION
;
5745 ((PCDROM_SUB_Q_DATA_FORMAT
) currentBuffer
)->Track
= 0;
5748 // Create notification event object to be used to signal the
5749 // request completion.
5752 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
5755 // Build the synchronous request to be sent to the port driver
5756 // to perform the request.
5759 irp
= IoBuildDeviceIoControlRequest(IOCTL_CDROM_READ_Q_CHANNEL
,
5760 deviceExtension
->DeviceObject
,
5762 sizeof(CDROM_SUB_Q_DATA_FORMAT
),
5764 sizeof(SUB_Q_CURRENT_POSITION
),
5770 ExFreePool(currentBuffer
);
5775 // Pass request to port driver and wait for request to complete.
5778 status
= IoCallDriver(deviceExtension
->DeviceObject
, irp
);
5780 if (status
== STATUS_PENDING
) {
5781 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
5782 status
= ioStatus
.Status
;
5785 if (!NT_SUCCESS(status
)) {
5786 ExFreePool(currentBuffer
);
5790 ExFreePool(currentBuffer
);
5792 return(PLAY_ACTIVE(deviceExtension
));
5796 IO_COMPLETION_ROUTINE CdRomMediaChangeCompletion
;
5799 CdRomMediaChangeCompletion(
5800 PDEVICE_OBJECT DeviceObject
,
5807 Routine Description:
5809 This routine handles the completion of the test unit ready irps
5810 used to determine if the media has changed. If the media has
5811 changed, this code signals the named event to wake up other
5812 system services that react to media change (aka AutoPlay).
5816 DeviceObject - the object for the completion
5817 Irp - the IRP being completed
5818 Context - the SRB from the IRP
5827 PSCSI_REQUEST_BLOCK srb
= (PSCSI_REQUEST_BLOCK
) Context
;
5828 PIO_STACK_LOCATION cdStack
= IoGetCurrentIrpStackLocation(Irp
);
5829 PIO_STACK_LOCATION irpNextStack
= IoGetNextIrpStackLocation(Irp
);
5830 PDEVICE_EXTENSION deviceExtension
;
5831 PDEVICE_EXTENSION physicalExtension
;
5832 PSENSE_DATA senseBuffer
;
5837 DeviceObject
= cdStack
->DeviceObject
;
5838 ASSERT(DeviceObject
);
5840 deviceExtension
= DeviceObject
->DeviceExtension
;
5841 physicalExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
5842 cddata
= (PCDROM_DATA
)(deviceExtension
+ 1);
5844 ASSERT(cddata
->MediaChangeIrp
== NULL
);
5847 // If the sense data field is valid, look for a media change.
5848 // otherwise this iteration of the polling will just assume nothing
5852 DebugPrint((3, "CdRomMediaChangeHandler: Completing Autorun Irp 0x%lx "
5854 Irp
, deviceExtension
->DeviceNumber
));
5856 if (srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) {
5857 if (srb
->SenseInfoBufferLength
>= FIELD_OFFSET(SENSE_DATA
, CommandSpecificInformation
)) {
5860 // See if this is a media change.
5863 senseBuffer
= srb
->SenseInfoBuffer
;
5864 if ((senseBuffer
->SenseKey
& 0x0f) == SCSI_SENSE_UNIT_ATTENTION
) {
5865 if (senseBuffer
->AdditionalSenseCode
== SCSI_ADSENSE_MEDIUM_CHANGED
) {
5867 DebugPrint((1, "CdRomMediaChangeCompletion: New media inserted "
5868 "into CdRom%d [irp = 0x%lx]\n",
5869 deviceExtension
->DeviceNumber
, Irp
));
5872 // Media change event occurred - signal the named event.
5875 KeSetEvent(deviceExtension
->MediaChangeEvent
,
5879 deviceExtension
->MediaChangeNoMedia
= FALSE
;
5883 if (DeviceObject
->Vpb
->Flags
& VPB_MOUNTED
) {
5886 // Must remember the media changed and force the
5887 // file system to verify on next access
5890 DeviceObject
->Flags
|= DO_VERIFY_VOLUME
;
5893 physicalExtension
->MediaChangeCount
++;
5895 } else if(((senseBuffer
->SenseKey
& 0x0f) == SCSI_SENSE_NOT_READY
)&&
5896 (senseBuffer
->AdditionalSenseCode
== SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
)&&
5897 (!deviceExtension
->MediaChangeNoMedia
)){
5900 // If there was no media in the device then signal the waiters if
5901 // we haven't already done so before.
5904 DebugPrint((1, "CdRomMediaChangeCompletion: No media in device"
5905 "CdRom%d [irp = 0x%lx]\n",
5906 deviceExtension
->DeviceNumber
, Irp
));
5908 KeSetEvent(deviceExtension
->MediaChangeEvent
,
5912 deviceExtension
->MediaChangeNoMedia
= TRUE
;
5916 } else if((srb
->SrbStatus
== SRB_STATUS_SUCCESS
)&&
5917 (deviceExtension
->MediaChangeNoMedia
)) {
5919 // We didn't have any media before and now the requests are succeeding
5920 // we probably missed the Media change somehow. Signal the change
5924 DebugPrint((1, "CdRomMediaChangeCompletion: Request completed normally"
5925 "for CdRom%d which was marked w/NoMedia [irp = 0x%lx]\n",
5926 deviceExtension
->DeviceNumber
, Irp
));
5928 KeSetEvent(deviceExtension
->MediaChangeEvent
,
5932 deviceExtension
->MediaChangeNoMedia
= FALSE
;
5936 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
5937 ScsiClassReleaseQueue(deviceExtension
->DeviceObject
);
5941 // Remember the IRP and SRB for use the next time.
5944 irpNextStack
->Parameters
.Scsi
.Srb
= srb
;
5945 cddata
->MediaChangeIrp
= Irp
;
5947 if (deviceExtension
->ClassError
) {
5953 // Throw away the status and retry values. Just give the error routine a chance
5954 // to do what it needs to.
5957 deviceExtension
->ClassError(DeviceObject
,
5963 IoStartNextPacket(DeviceObject
, FALSE
);
5965 return STATUS_MORE_PROCESSING_REQUIRED
;
5971 IN PDEVICE_OBJECT DeviceObject
,
5977 Routine Description:
5979 This routine handles the once per second timer provided by the
5980 Io subsystem. It is only used when the cdrom device itself is
5981 a candidate for autoplay support. It should never be called if
5982 the cdrom device is a changer device.
5986 DeviceObject - what to check.
5999 PLIST_ENTRY listEntry
;
6001 PIO_STACK_LOCATION irpStack
;
6002 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
6004 cddata
= (PCDROM_DATA
)(deviceExtension
+ 1);
6006 if (cddata
->MediaChange
) {
6007 if (cddata
->MediaChangeIrp
!= NULL
) {
6010 // Media change support is active and the IRP is waiting.
6011 // Decrement the timer.
6012 // There is no MP protection on the timer counter. This
6013 // code is the only code that will manipulate the timer
6014 // and only one instance of it should be running at any
6018 cddata
->MediaChangeCountDown
--;
6021 cddata
->MediaChangeIrpTimeInUse
= 0;
6022 cddata
->MediaChangeIrpLost
= FALSE
;
6025 if (!cddata
->MediaChangeCountDown
) {
6026 PSCSI_REQUEST_BLOCK srb
;
6027 PIO_STACK_LOCATION irpNextStack
;
6034 cddata
->MediaChangeCountDown
= MEDIA_CHANGE_DEFAULT_TIME
;
6037 // Prepare the IRP for the test unit ready
6040 irp
= cddata
->MediaChangeIrp
;
6041 cddata
->MediaChangeIrp
= NULL
;
6043 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
6044 irp
->IoStatus
.Information
= 0;
6046 irp
->UserBuffer
= NULL
;
6049 // If the irp is sent down when the volume needs to be
6050 // verified, CdRomUpdateGeometryCompletion won't complete
6051 // it since it's not associated with a thread. Marking
6052 // it to override the verify causes it always be sent
6053 // to the port driver
6056 irpStack
= IoGetCurrentIrpStackLocation(irp
);
6057 irpStack
->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
6059 irpNextStack
= IoGetNextIrpStackLocation(irp
);
6060 irpNextStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
6061 irpNextStack
->Parameters
.DeviceIoControl
.IoControlCode
=
6062 IOCTL_SCSI_EXECUTE_NONE
;
6065 // Prepare the SRB for execution.
6068 srb
= irpNextStack
->Parameters
.Scsi
.Srb
;
6069 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
6071 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
6072 srb
->PathId
= deviceExtension
->PathId
;
6073 srb
->TargetId
= deviceExtension
->TargetId
;
6074 srb
->Lun
= deviceExtension
->Lun
;
6075 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
6076 srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
|
6077 SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
6078 srb
->DataTransferLength
= 0;
6079 srb
->OriginalRequest
= irp
;
6081 RtlZeroMemory(srb
->SenseInfoBuffer
, SENSE_BUFFER_SIZE
);
6082 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
6084 cdb
= (PCDB
) &srb
->Cdb
[0];
6085 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_TEST_UNIT_READY
;
6086 cdb
->CDB6GENERIC
.LogicalUnitNumber
= srb
->Lun
;
6089 // Setup the IRP to perform a test unit ready.
6092 IoSetCompletionRoutine(irp
,
6093 CdRomMediaChangeCompletion
,
6100 // Issue the request.
6103 IoStartPacket(DeviceObject
, irp
, NULL
, NULL
);
6108 if(cddata
->MediaChangeIrpLost
== FALSE
) {
6109 if(cddata
->MediaChangeIrpTimeInUse
++ >
6110 MEDIA_CHANGE_TIMEOUT_TIME
) {
6112 DebugPrint((0, "CdRom%d: AutoPlay has lost it's irp and "
6113 "doesn't know where to find it. Leave it "
6114 "alone and it'll come home dragging it's "
6115 "stack behind it.\n",
6116 deviceExtension
->DeviceNumber
));
6117 cddata
->MediaChangeIrpLost
= TRUE
;
6126 // Process all generic timer IRPS in the timer list. As IRPs are pulled
6127 // off of the TimerIrpList they must be remembered in the first loop
6128 // if they are not sent to the lower driver. After all items have
6129 // been pulled off the list, it is possible to put the held IRPs back
6130 // into the TimerIrpList.
6134 if (IsListEmpty(&cddata
->TimerIrpList
)) {
6137 listEntry
= ExInterlockedRemoveHeadList(&cddata
->TimerIrpList
,
6138 &cddata
->TimerIrpSpinLock
);
6143 // There is something in the timer list. Pick up the IRP and
6144 // see if it is ready to be submitted.
6147 irp
= CONTAINING_RECORD(listEntry
, IRP
, Tail
.Overlay
.ListEntry
);
6148 irpStack
= IoGetCurrentIrpStackLocation(irp
);
6150 if (irpStack
->Parameters
.Others
.Argument3
) {
6154 // Decrement the countdown timer and put the IRP back in the list.
6157 count
= (ULONG_PTR
) irpStack
->Parameters
.Others
.Argument3
;
6159 irpStack
->Parameters
.Others
.Argument3
= (PVOID
) count
;
6161 ASSERT(irp
->AssociatedIrp
.MasterIrp
== NULL
);
6163 irp
->AssociatedIrp
.MasterIrp
= (PVOID
) heldIrpList
;
6170 // Submit this IRP to the lower driver. This IRP does not
6171 // need to be remembered here. It will be handled again when
6175 DebugPrint((1, "CdRomTickHandler: Reissuing request %lx (thread = %lx)\n", irp
, irp
->Tail
.Overlay
.Thread
));
6178 // feed this to the appropriate port driver
6181 IoCallDriver (deviceExtension
->PortDeviceObject
, irp
);
6186 // Pick up the next IRP from the timer list.
6189 listEntry
= ExInterlockedRemoveHeadList(&cddata
->TimerIrpList
,
6190 &cddata
->TimerIrpSpinLock
);
6194 // Move all held IRPs back onto the timer list.
6197 while (heldIrpList
) {
6200 // Save the single list pointer before queueing this IRP.
6203 nextIrp
= (PIRP
) heldIrpList
->AssociatedIrp
.MasterIrp
;
6204 heldIrpList
->AssociatedIrp
.MasterIrp
= NULL
;
6207 // Return the held IRP to the timer list.
6210 ExInterlockedInsertTailList(&cddata
->TimerIrpList
,
6211 &heldIrpList
->Tail
.Overlay
.ListEntry
,
6212 &cddata
->TimerIrpSpinLock
);
6215 // Continue processing the held IRPs
6218 heldIrpList
= nextIrp
;
6224 CdRomCheckRegistryForMediaChangeValue(
6225 IN PUNICODE_STRING RegistryPath
,
6226 IN ULONG DeviceNumber
6231 Routine Description:
6233 The user must specify that AutoPlay is to run on the platform
6234 by setting the registry value HKEY_LOCAL_MACHINE\System\CurrentControlSet\
6235 Services\Cdrom\Autorun:REG_DWORD:1.
6237 The user can override the global setting to enable or disable Autorun on a
6238 specific cdrom device by setting the key HKEY_LOCAL_MACHINE\System\
6239 CurrentControlSet\Services\Cdrom\Device<N>\Autorun:REG_DWORD to one or zero.
6240 (CURRENTLY UNIMPLEMENTED)
6242 If this registry value does not exist or contains the value zero then
6243 the timer to check for media change does not run.
6247 RegistryPath - pointer to the unicode string inside
6248 ...\CurrentControlSet\Services\Cdrom
6249 DeviceNumber - The number of the device object
6253 TRUE - Autorun is enabled.
6259 #define ITEMS_TO_QUERY 2 /* always 1 greater than what is searched */
6260 PRTL_QUERY_REGISTRY_TABLE parameters
= NULL
;
6268 ANSI_STRING paramNum
;
6270 UNICODE_STRING paramStr
;
6272 UNICODE_STRING paramSuffix
;
6273 UNICODE_STRING paramPath
;
6274 UNICODE_STRING paramDevPath
;
6277 // First append \Parameters to the passed in registry path
6280 RtlInitUnicodeString(¶mStr
, L
"\\Parameters");
6282 RtlInitUnicodeString(¶mPath
, NULL
);
6284 paramPath
.MaximumLength
= RegistryPath
->Length
+
6288 paramPath
.Buffer
= ExAllocatePool(PagedPool
, paramPath
.MaximumLength
);
6290 if(!paramPath
.Buffer
) {
6292 DebugPrint((1,"CdRomCheckRegAP: couldn't allocate paramPath\n"));
6297 RtlZeroMemory(paramPath
.Buffer
, paramPath
.MaximumLength
);
6298 RtlAppendUnicodeToString(¶mPath
, RegistryPath
->Buffer
);
6299 RtlAppendUnicodeToString(¶mPath
, paramStr
.Buffer
);
6301 DebugPrint((2, "CdRomCheckRegAP: paramPath [%d] = %ws\n",
6306 // build a counted ANSI string that contains
6307 // the suffix for the path
6310 sprintf(buf
, "\\Device%lu", DeviceNumber
);
6311 RtlInitAnsiString(¶mNum
, buf
);
6314 // Next convert this into a unicode string
6317 status
= RtlAnsiStringToUnicodeString(¶mSuffix
, ¶mNum
, TRUE
);
6319 if(!NT_SUCCESS(status
)) {
6320 DebugPrint((1,"CdRomCheckRegAP: couldn't convert paramNum to paramSuffix\n"));
6321 ExFreePool(paramPath
.Buffer
);
6325 RtlInitUnicodeString(¶mDevPath
, NULL
);
6328 // now build the device specific path
6331 paramDevPath
.MaximumLength
= paramPath
.Length
+
6332 paramSuffix
.Length
+
6334 paramDevPath
.Buffer
= ExAllocatePool(PagedPool
, paramDevPath
.MaximumLength
);
6336 if(!paramDevPath
.Buffer
) {
6337 RtlFreeUnicodeString(¶mSuffix
);
6338 ExFreePool(paramPath
.Buffer
);
6342 RtlZeroMemory(paramDevPath
.Buffer
, paramDevPath
.MaximumLength
);
6343 RtlAppendUnicodeToString(¶mDevPath
, paramPath
.Buffer
);
6344 RtlAppendUnicodeToString(¶mDevPath
, paramSuffix
.Buffer
);
6346 DebugPrint((2, "CdRomCheckRegAP: paramDevPath [%d] = %ws\n",
6350 parameters
= ExAllocatePool(NonPagedPool
,
6351 sizeof(RTL_QUERY_REGISTRY_TABLE
)*ITEMS_TO_QUERY
);
6356 // Check for the Autorun value.
6359 RtlZeroMemory(parameters
,
6360 (sizeof(RTL_QUERY_REGISTRY_TABLE
)*ITEMS_TO_QUERY
));
6362 parameters
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
6363 parameters
[0].Name
= L
"Autorun";
6364 parameters
[0].EntryContext
= &doRun
;
6365 parameters
[0].DefaultType
= REG_DWORD
;
6366 parameters
[0].DefaultData
= &zero
;
6367 parameters
[0].DefaultLength
= sizeof(ULONG
);
6369 status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
| RTL_REGISTRY_OPTIONAL
,
6370 RegistryPath
->Buffer
,
6375 DebugPrint((2, "CdRomCheckRegAP: cdrom/Autorun flag = %d\n", doRun
));
6377 RtlZeroMemory(parameters
,
6378 (sizeof(RTL_QUERY_REGISTRY_TABLE
)*ITEMS_TO_QUERY
));
6380 parameters
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
6381 parameters
[0].Name
= L
"Autorun";
6382 parameters
[0].EntryContext
= &tmp
;
6383 parameters
[0].DefaultType
= REG_DWORD
;
6384 parameters
[0].DefaultData
= &doRun
;
6385 parameters
[0].DefaultLength
= sizeof(ULONG
);
6387 status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
| RTL_REGISTRY_OPTIONAL
,
6393 DebugPrint((2, "CdRomCheckRegAP: cdrom/parameters/autorun flag = %d\n", tmp
));
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
= &tmp
;
6403 parameters
[0].DefaultLength
= sizeof(ULONG
);
6405 status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
| RTL_REGISTRY_OPTIONAL
,
6406 paramDevPath
.Buffer
,
6411 DebugPrint((1, "CdRomCheckRegAP: cdrom/parameters/device%d/autorun flag = %d\n", DeviceNumber
, doRun
));
6413 ExFreePool(parameters
);
6417 ExFreePool(paramPath
.Buffer
);
6418 ExFreePool(paramDevPath
.Buffer
);
6419 RtlFreeUnicodeString(¶mSuffix
);
6421 DebugPrint((1, "CdRomCheckRegAP: Autoplay for device %d is %s\n",
6423 (doRun
? "on" : "off")));
6436 IN PDEVICE_OBJECT DeviceObject
,
6443 Routine Description:
6445 This routine is called by DriverEntry to determine whether a Sanyo 3-CD
6446 changer device is present.
6450 DeviceObject - Supplies the device object for the 'real' device.
6456 TRUE - if an Atapi changer device is found.
6463 PCHAR inquiryBuffer
;
6464 IO_STATUS_BLOCK ioStatus
;
6466 PSCSI_ADAPTER_BUS_INFO adapterInfo
;
6468 PINQUIRYDATA inquiryData
;
6469 PSCSI_INQUIRY_DATA lunInfo
;
6471 inquiryBuffer
= ExAllocatePool(NonPagedPool
, 2048);
6472 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
6473 irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA
,
6486 status
= IoCallDriver(DeviceObject
, irp
);
6488 if (status
== STATUS_PENDING
) {
6489 KeWaitForSingleObject(&event
, Executive
, KernelMode
, FALSE
, NULL
);
6490 status
= ioStatus
.Status
;
6493 if (!NT_SUCCESS(status
)) {
6497 adapterInfo
= (PVOID
) inquiryBuffer
;
6499 for (scsiBus
=0; scsiBus
< (ULONG
)adapterInfo
->NumberOfBuses
; scsiBus
++) {
6502 // Get the SCSI bus scan data for this bus.
6505 lunInfo
= (PVOID
) (inquiryBuffer
+ adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
);
6509 if (lunInfo
->PathId
== PathId
&& lunInfo
->TargetId
== TargetId
) {
6511 inquiryData
= (PVOID
) lunInfo
->InquiryData
;
6513 if (RtlCompareMemory(inquiryData
->VendorId
, "TORiSAN CD-ROM CDR-C", 20) == 20) {
6514 ExFreePool(inquiryBuffer
);
6518 ExFreePool(inquiryBuffer
);
6522 if (!lunInfo
->NextInquiryDataOffset
) {
6526 lunInfo
= (PVOID
) (inquiryBuffer
+ lunInfo
->NextInquiryDataOffset
);
6530 ExFreePool(inquiryBuffer
);
6536 IsThisAnAtapiChanger(
6537 IN PDEVICE_OBJECT DeviceObject
,
6538 OUT PULONG DiscsPresent
6543 Routine Description:
6545 This routine is called by DriverEntry to determine whether an Atapi
6546 changer device is present.
6550 DeviceObject - Supplies the device object for the 'real' device.
6552 DiscsPresent - Supplies a pointer to the number of Discs supported by the changer.
6556 TRUE - if an Atapi changer device is found.
6561 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
6562 PMECHANICAL_STATUS_INFORMATION_HEADER mechanicalStatusBuffer
;
6564 SCSI_REQUEST_BLOCK srb
;
6565 PCDB cdb
= (PCDB
) &srb
.Cdb
[0];
6566 BOOLEAN retVal
= FALSE
;
6571 // Some devices can't handle 12 byte CDB's gracefully
6574 if(deviceExtension
->DeviceFlags
& DEV_NO_12BYTE_CDB
) {
6581 // Build and issue the mechanical status command.
6584 mechanicalStatusBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
6585 sizeof(MECHANICAL_STATUS_INFORMATION_HEADER
));
6587 if (!mechanicalStatusBuffer
) {
6592 // Build and send the Mechanism status CDB.
6595 RtlZeroMemory(&srb
, sizeof(srb
));
6598 srb
.TimeOutValue
= 20;
6600 cdb
->MECH_STATUS
.OperationCode
= SCSIOP_MECHANISM_STATUS
;
6601 cdb
->MECH_STATUS
.AllocationLength
[1] = sizeof(MECHANICAL_STATUS_INFORMATION_HEADER
);
6603 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
6605 mechanicalStatusBuffer
,
6606 sizeof(MECHANICAL_STATUS_INFORMATION_HEADER
),
6610 if (status
== STATUS_SUCCESS
) {
6613 // Indicate number of slots available
6616 *DiscsPresent
= mechanicalStatusBuffer
->NumberAvailableSlots
;
6617 if (*DiscsPresent
> 1) {
6622 // If only one disc, no need for this driver.
6630 // Device doesn't support this command.
6636 ExFreePool(mechanicalStatusBuffer
);
6644 IsThisAMultiLunDevice(
6645 IN PDEVICE_OBJECT DeviceObject
,
6646 IN PDEVICE_OBJECT PortDeviceObject
6650 Routine Description:
6652 This routine is called to determine whether a multi-lun
6657 DeviceObject - Supplies the device object for the 'real' device.
6661 TRUE - if a Multi-lun device is found.
6666 PSCSI_INQUIRY_DATA lunInfo
;
6667 PSCSI_ADAPTER_BUS_INFO adapterInfo
;
6668 PDEVICE_EXTENSION deviceExtension
= (PDEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
6669 PINQUIRYDATA inquiryData
;
6674 status
= ScsiClassGetInquiryData(PortDeviceObject
, (PSCSI_ADAPTER_BUS_INFO
*) &buffer
);
6676 if (!NT_SUCCESS(status
)) {
6677 DebugPrint((1,"IsThisAMultiLunDevice: ScsiClassGetInquiryData failed\n"));
6681 adapterInfo
= (PVOID
) buffer
;
6684 // For each SCSI bus this adapter supports ...
6687 for (scsiBus
=0; scsiBus
< adapterInfo
->NumberOfBuses
; scsiBus
++) {
6690 // Get the SCSI bus scan data for this bus.
6693 lunInfo
= (PVOID
) (buffer
+ adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
);
6695 while (adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
) {
6697 inquiryData
= (PVOID
)lunInfo
->InquiryData
;
6699 if ((lunInfo
->PathId
== deviceExtension
->PathId
) &&
6700 (lunInfo
->TargetId
== deviceExtension
->TargetId
) &&
6701 (inquiryData
->DeviceType
== READ_ONLY_DIRECT_ACCESS_DEVICE
)) {
6703 DebugPrint((1,"IsThisAMultiLunDevice: Vendor string is %.24s\n",
6704 inquiryData
->VendorId
));
6707 // If this device has more than one cdrom-type lun then we
6708 // won't support autoplay on it
6718 // Get next LunInfo.
6721 if (lunInfo
->NextInquiryDataOffset
== 0) {
6725 lunInfo
= (PVOID
) (buffer
+ lunInfo
->NextInquiryDataOffset
);
6734 IO_COMPLETION_ROUTINE CdRomUpdateGeometryCompletion
;
6737 CdRomUpdateGeometryCompletion(
6738 PDEVICE_OBJECT DeviceObject
,
6745 Routine Description:
6747 This routine andles the completion of the test unit ready irps
6748 used to determine if the media has changed. If the media has
6749 changed, this code signals the named event to wake up other
6750 system services that react to media change (aka AutoPlay).
6754 DeviceObject - the object for the completion
6755 Irp - the IRP being completed
6756 Context - the SRB from the IRP
6765 PSCSI_REQUEST_BLOCK srb
= (PSCSI_REQUEST_BLOCK
) Context
;
6766 PREAD_CAPACITY_DATA readCapacityBuffer
;
6767 PDEVICE_EXTENSION deviceExtension
;
6768 PIO_STACK_LOCATION irpStack
;
6771 ULONG_PTR retryCount
;
6777 // Get items saved in the private IRP stack location.
6780 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
6781 retryCount
= (ULONG_PTR
) irpStack
->Parameters
.Others
.Argument1
;
6782 originalIrp
= (PIRP
) irpStack
->Parameters
.Others
.Argument2
;
6784 if (!DeviceObject
) {
6785 DeviceObject
= irpStack
->DeviceObject
;
6787 ASSERT(DeviceObject
);
6789 deviceExtension
= DeviceObject
->DeviceExtension
;
6790 cddata
= (PCDROM_DATA
) (deviceExtension
+ 1);
6791 readCapacityBuffer
= srb
->DataBuffer
;
6793 if ((NT_SUCCESS(Irp
->IoStatus
.Status
)) && (SRB_STATUS(srb
->SrbStatus
) == SRB_STATUS_SUCCESS
)) {
6797 DebugPrint((2, "CdRomUpdateCapacityCompletion: [%lx] successful completion of buddy-irp %lx\n", originalIrp
, Irp
));
6799 // Copy sector size from read capacity buffer to device extension
6800 // in reverse byte order.
6803 from
= (PFOUR_BYTE
) &readCapacityBuffer
->BytesPerBlock
;
6804 to
= (PFOUR_BYTE
) &deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
;
6805 to
->Byte0
= from
->Byte3
;
6806 to
->Byte1
= from
->Byte2
;
6807 to
->Byte2
= from
->Byte1
;
6808 to
->Byte3
= from
->Byte0
;
6811 // Using the new BytesPerBlock, calculate and store the SectorShift.
6814 WHICH_BIT(deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
, deviceExtension
->SectorShift
);
6817 // Copy last sector in reverse byte order.
6820 from
= (PFOUR_BYTE
) &readCapacityBuffer
->LogicalBlockAddress
;
6821 to
= (PFOUR_BYTE
) &lastSector
;
6822 to
->Byte0
= from
->Byte3
;
6823 to
->Byte1
= from
->Byte2
;
6824 to
->Byte2
= from
->Byte1
;
6825 to
->Byte3
= from
->Byte0
;
6826 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(lastSector
+ 1);
6829 // Calculate number of cylinders.
6832 deviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
= (LONGLONG
)((lastSector
+ 1)/(32 * 64));
6833 deviceExtension
->PartitionLength
.QuadPart
=
6834 (deviceExtension
->PartitionLength
.QuadPart
<< deviceExtension
->SectorShift
);
6835 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= RemovableMedia
;
6838 // Assume sectors per track are 32;
6841 deviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
= 32;
6844 // Assume tracks per cylinder (number of heads) is 64.
6847 deviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
= 64;
6851 DebugPrint((1, "CdRomUpdateCapacityCompletion: [%lx] unsuccessful completion of buddy-irp %lx (status - %lx)\n", originalIrp
, Irp
, Irp
->IoStatus
.Status
));
6853 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
6854 ScsiClassReleaseQueue(DeviceObject
);
6857 retry
= ScsiClassInterpretSenseInfo(DeviceObject
,
6868 DebugPrint((1, "CdRomUpdateCapacityCompletion: [%lx] Retrying request %lx .. thread is %lx\n", originalIrp
, Irp
, Irp
->Tail
.Overlay
.Thread
));
6870 // set up a one shot timer to get this process started over
6873 irpStack
->Parameters
.Others
.Argument1
= (PVOID
) retryCount
;
6874 irpStack
->Parameters
.Others
.Argument2
= (PVOID
) originalIrp
;
6875 irpStack
->Parameters
.Others
.Argument3
= (PVOID
) 2;
6878 // Setup the IRP to be submitted again in the timer routine.
6881 irpStack
= IoGetNextIrpStackLocation(Irp
);
6882 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
6883 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
6884 irpStack
->Parameters
.Scsi
.Srb
= srb
;
6885 IoSetCompletionRoutine(Irp
,
6886 CdRomUpdateGeometryCompletion
,
6893 // Set up the SRB for read capacity.
6896 srb
->CdbLength
= 10;
6897 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
6898 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
6900 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
6901 srb
->PathId
= deviceExtension
->PathId
;
6902 srb
->TargetId
= deviceExtension
->TargetId
;
6903 srb
->Lun
= deviceExtension
->Lun
;
6904 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
6905 srb
->SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
6906 srb
->DataTransferLength
= sizeof(READ_CAPACITY_DATA
);
6912 cdb
= (PCDB
) &srb
->Cdb
[0];
6913 cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
6914 cdb
->CDB10
.LogicalUnitNumber
= deviceExtension
->Lun
;
6917 // Requests queued onto this list will be sent to the
6918 // lower level driver during CdRomTickHandler
6921 ExInterlockedInsertHeadList(&cddata
->TimerIrpList
,
6922 &Irp
->Tail
.Overlay
.ListEntry
,
6923 &cddata
->TimerIrpSpinLock
);
6925 return STATUS_MORE_PROCESSING_REQUIRED
;
6929 // This has been bounced for a number of times. Error the
6930 // original request.
6933 originalIrp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
6934 RtlZeroMemory(deviceExtension
->DiskGeometry
, sizeof(DISK_GEOMETRY_EX
));
6935 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= 2048;
6936 deviceExtension
->SectorShift
= 11;
6937 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(0x7fffffff);
6938 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= RemovableMedia
;
6943 // Set up reasonable defaults
6946 RtlZeroMemory(deviceExtension
->DiskGeometry
, sizeof(DISK_GEOMETRY_EX
));
6947 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= 2048;
6948 deviceExtension
->SectorShift
= 11;
6949 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(0x7fffffff);
6950 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= RemovableMedia
;
6955 // Free resources held.
6958 ExFreePool(srb
->SenseInfoBuffer
);
6959 ExFreePool(srb
->DataBuffer
);
6961 if (Irp
->MdlAddress
) {
6962 IoFreeMdl(Irp
->MdlAddress
);
6965 if (originalIrp
->Tail
.Overlay
.Thread
) {
6967 DebugPrint((2, "CdRomUpdateCapacityCompletion: [%lx] completing original IRP\n", originalIrp
));
6968 IoCompleteRequest(originalIrp
, IO_DISK_INCREMENT
);
6971 DebugPrint((1, "CdRomUpdateCapacityCompletion: [%lx] original irp has "
6978 // It's now safe to either start the next request or let the waiting ioctl
6979 // request continue along it's merry way
6982 IoStartNextPacket(DeviceObject
, FALSE
);
6984 return STATUS_MORE_PROCESSING_REQUIRED
;
6989 CdRomUpdateCapacity(
6990 IN PDEVICE_EXTENSION DeviceExtension
,
6991 IN PIRP IrpToComplete
,
6992 IN OPTIONAL PKEVENT IoctlEvent
6997 Routine Description:
6999 This routine updates the capacity of the disk as recorded in the device extension.
7000 It also completes the IRP given with STATUS_VERIFY_REQUIRED. This routine is called
7001 when a media change has occurred and it is necessary to determine the capacity of the
7002 new media prior to the next access.
7006 DeviceExtension - the device to update
7007 IrpToComplete - the request that needs to be completed when done.
7018 PSCSI_REQUEST_BLOCK srb
;
7019 PREAD_CAPACITY_DATA capacityBuffer
;
7020 PIO_STACK_LOCATION irpStack
;
7023 irp
= IoAllocateIrp((CCHAR
)(DeviceExtension
->DeviceObject
->StackSize
+1),
7028 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
7030 capacityBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
7031 sizeof(READ_CAPACITY_DATA
));
7033 if (capacityBuffer
) {
7036 senseBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
7040 irp
->MdlAddress
= IoAllocateMdl(capacityBuffer
,
7041 sizeof(READ_CAPACITY_DATA
),
7046 if (irp
->MdlAddress
) {
7049 // Have all resources. Set up the IRP to send for the capacity.
7052 IoSetNextIrpStackLocation(irp
);
7053 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
7054 irp
->IoStatus
.Information
= 0;
7056 irp
->UserBuffer
= NULL
;
7059 // Save the device object and retry count in a private stack location.
7062 irpStack
= IoGetCurrentIrpStackLocation(irp
);
7063 irpStack
->DeviceObject
= DeviceExtension
->DeviceObject
;
7064 irpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
7065 irpStack
->Parameters
.Others
.Argument2
= (PVOID
) IrpToComplete
;
7068 // Construct the IRP stack for the lower level driver.
7071 irpStack
= IoGetNextIrpStackLocation(irp
);
7072 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
7073 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
7074 irpStack
->Parameters
.Scsi
.Srb
= srb
;
7075 IoSetCompletionRoutine(irp
,
7076 CdRomUpdateGeometryCompletion
,
7085 MmBuildMdlForNonPagedPool(irp
->MdlAddress
);
7089 // Set up the SRB for read capacity.
7092 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
7093 RtlZeroMemory(senseBuffer
, SENSE_BUFFER_SIZE
);
7094 srb
->CdbLength
= 10;
7095 srb
->TimeOutValue
= DeviceExtension
->TimeOutValue
;
7096 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
7098 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
7099 srb
->PathId
= DeviceExtension
->PathId
;
7100 srb
->TargetId
= DeviceExtension
->TargetId
;
7101 srb
->Lun
= DeviceExtension
->Lun
;
7102 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
7103 srb
->SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
7104 srb
->DataBuffer
= capacityBuffer
;
7105 srb
->DataTransferLength
= sizeof(READ_CAPACITY_DATA
);
7106 srb
->OriginalRequest
= irp
;
7107 srb
->SenseInfoBuffer
= senseBuffer
;
7108 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
7114 cdb
= (PCDB
) &srb
->Cdb
[0];
7115 cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
7116 cdb
->CDB10
.LogicalUnitNumber
= DeviceExtension
->Lun
;
7119 // Set the return value in the IRP that will be completed
7120 // upon completion of the read capacity.
7123 IrpToComplete
->IoStatus
.Status
= STATUS_VERIFY_REQUIRED
;
7124 IoMarkIrpPending(IrpToComplete
);
7126 IoCallDriver(DeviceExtension
->PortDeviceObject
, irp
);
7129 // status is not checked because the completion routine for this
7130 // IRP will always get called and it will free the resources.
7133 return STATUS_PENDING
;
7136 ExFreePool(senseBuffer
);
7137 ExFreePool(capacityBuffer
);
7142 ExFreePool(capacityBuffer
);
7155 return STATUS_INSUFFICIENT_RESOURCES
;
7160 CdRomClassIoctlCompletion(
7161 IN PDEVICE_OBJECT DeviceObject
,
7168 Routine Description:
7170 This routine signals the event used by CdRomDeviceControl to synchronize
7171 class driver (and lower level driver) ioctls with cdrom's startio routine.
7172 The irp completion is short-circuited so that CdRomDeviceControl can
7173 reissue it once it wakes up.
7177 DeviceObject - the device object
7178 Irp - the request we are synchronizing
7179 Context - a PKEVENT that we need to signal
7188 PKEVENT syncEvent
= (PKEVENT
) Context
;
7190 DebugPrint((2, "CdRomClassIoctlCompletion: setting event for irp %#08lx\n",
7194 KeSetEvent(syncEvent
, IO_DISK_INCREMENT
, FALSE
);
7196 return STATUS_MORE_PROCESSING_REQUIRED
;