2 * PROJECT: ReactOS Storage Stack
3 * LICENSE: DDK - see license.txt in the root dir
4 * FILE: drivers/storage/cdrom/cdrom.c
5 * PURPOSE: CDROM driver
6 * PROGRAMMERS: Based on a source code sample from Microsoft NT4 DDK
14 #include <include/class2.h>
20 #define CDB12GENERIC_LENGTH 12
22 typedef struct _XA_CONTEXT
{
25 // Pointer to the device object.
28 PDEVICE_OBJECT DeviceObject
;
31 // Pointer to the original request when
32 // a mode select must be sent.
38 // Pointer to the mode select srb.
41 PSCSI_REQUEST_BLOCK Srb
;
42 } XA_CONTEXT
, *PXA_CONTEXT
;
44 typedef struct _ERROR_RECOVERY_DATA
{
45 MODE_PARAMETER_HEADER Header
;
46 MODE_PARAMETER_BLOCK BlockDescriptor
;
47 MODE_READ_RECOVERY_PAGE ReadRecoveryPage
;
48 } ERROR_RECOVERY_DATA
, *PERROR_RECOVERY_DATA
;
50 typedef struct _ERROR_RECOVERY_DATA10
{
51 MODE_PARAMETER_HEADER10 Header10
;
52 MODE_PARAMETER_BLOCK BlockDescriptor10
;
53 MODE_READ_RECOVERY_PAGE ReadRecoveryPage10
;
54 } ERROR_RECOVERY_DATA10
, *PERROR_RECOVERY_DATA10
;
57 // CdRom specific addition to device extension.
60 typedef struct _CDROM_DATA
{
63 // Indicates whether an audio play operation
64 // is currently being performed.
70 // Indicates whether the blocksize used for user data
77 // Indicates whether 6 or 10 byte mode sense/select
84 // Storage for the error recovery page. This is used
85 // as an easy method to switch block sizes.
89 ERROR_RECOVERY_DATA u1
;
90 ERROR_RECOVERY_DATA10 u2
;
95 // Pointer to the original irp for the raw read.
101 // Used to protect accesses to the RawAccess flag.
104 KSPIN_LOCK FormSpinLock
;
107 // Even if media change support is requested, there are some devices
108 // that are not supported. This flag will indicate that such a device
109 // is present when it is FALSE.
112 BOOLEAN MediaChangeSupported
;
115 // The media change event is being supported. The media change timer
116 // should be running whenever this is true.
122 // The timer value to support media change events. This is a countdown
123 // value used to determine when to poll the device for a media change.
124 // The max value for the timer is 255 seconds.
127 UCHAR MediaChangeCountDown
;
131 // Second timer to keep track of how long the media change IRP has been
132 // in use. If this value exceeds the timeout (#defined) then we should
133 // print out a message to the user and set the MediaChangeIrpLost flag
136 SHORT MediaChangeIrpTimeInUse
;
139 // Set by CdRomTickHandler when we determine that the media change irp has
143 BOOLEAN MediaChangeIrpLost
;
146 UCHAR PadReserve
; // use this for new flags.
149 // An IRP is allocated and kept for the duration that media change
150 // detection is in effect. If this is NULL and MediaChange is TRUE,
151 // the detection is in progress. This should always be NULL when
152 // MediaChange is FALSE.
158 // The timer work list is a collection of IRPS that are prepared for
159 // submission, but need to allow some time to pass before they are
163 LIST_ENTRY TimerIrpList
;
164 KSPIN_LOCK TimerIrpSpinLock
;
166 } CDROM_DATA
, *PCDROM_DATA
;
168 #define DEVICE_EXTENSION_SIZE sizeof(DEVICE_EXTENSION) + sizeof(CDROM_DATA)
169 #define SCSI_CDROM_TIMEOUT 10
170 #define SCSI_CHANGER_BONUS_TIMEOUT 10
171 #define HITACHI_MODE_DATA_SIZE 12
172 #define MODE_DATA_SIZE 64
173 #define RAW_SECTOR_SIZE 2352
174 #define COOKED_SECTOR_SIZE 2048
175 #define MEDIA_CHANGE_DEFAULT_TIME 4
176 #define CDROM_SRB_LIST_SIZE 4
182 // Used to detect the loss of the autorun irp. The driver prints out a message
183 // (debug level 0) if this timeout ever occurs
185 #define MEDIA_CHANGE_TIMEOUT_TIME 300
189 #define PLAY_ACTIVE(DeviceExtension) (((PCDROM_DATA)(DeviceExtension + 1))->PlayActive)
191 #define MSF_TO_LBA(Minutes,Seconds,Frames) \
192 (ULONG)((60 * 75 * (Minutes)) + (75 * (Seconds)) + ((Frames) - 150))
194 #define LBA_TO_MSF(Lba,Minutes,Seconds,Frames) \
196 (Minutes) = (UCHAR)(Lba / (60 * 75)); \
197 (Seconds) = (UCHAR)((Lba % (60 * 75)) / 75); \
198 (Frames) = (UCHAR)((Lba % (60 * 75)) % 75); \
201 #define DEC_TO_BCD(x) (((x / 10) << 4) + (x % 10))
204 // Define flags for XA, CDDA, and Mode Select/Sense
207 #define XA_USE_6_BYTE 0x01
208 #define XA_USE_10_BYTE 0x02
209 #define XA_USE_READ_CD 0x04
210 #define XA_NOT_SUPPORTED 0x08
212 #define PLEXTOR_CDDA 0x10
213 #define NEC_CDDA 0x20
216 // Sector types for READ_CD
220 #define CD_DA_SECTOR 1
221 #define YELLOW_MODE1_SECTOR 2
222 #define YELLOW_MODE2_SECTOR 3
223 #define FORM2_MODE1_SECTOR 4
224 #define FORM2_MODE2_SECTOR 5
228 #ifdef ExAllocatePool
229 #undef ExAllocatePool
231 #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'CscS')
237 IN PDRIVER_OBJECT DriverObject
,
238 IN PUNICODE_STRING RegistryPath
243 ScsiCdRomFindDevices(
244 IN PDRIVER_OBJECT DriverObject
,
245 IN PUNICODE_STRING RegistryPath
,
246 IN PCLASS_INIT_DATA InitializationData
,
247 IN PDEVICE_OBJECT PortDeviceObject
,
254 IN PDEVICE_OBJECT DeviceObject
,
260 ScsiCdRomReadVerification(
261 IN PDEVICE_OBJECT DeviceObject
,
268 IN PDEVICE_OBJECT DeviceObject
,
270 IN PIRP OriginalRequest
276 IN PDEVICE_OBJECT DeviceObject
,
280 IO_COMPLETION_ROUTINE CdRomDeviceControlCompletion
;
283 CdRomDeviceControlCompletion(
284 IN PDEVICE_OBJECT DeviceObject
,
289 IO_COMPLETION_ROUTINE CdRomSetVolumeIntermediateCompletion
;
292 CdRomSetVolumeIntermediateCompletion(
293 IN PDEVICE_OBJECT DeviceObject
,
298 IO_COMPLETION_ROUTINE CdRomSwitchModeCompletion
;
301 CdRomSwitchModeCompletion(
302 IN PDEVICE_OBJECT DeviceObject
,
307 IO_COMPLETION_ROUTINE CdRomXACompletion
;
311 IN PDEVICE_OBJECT DeviceObject
,
316 IO_COMPLETION_ROUTINE CdRomClassIoctlCompletion
;
319 CdRomClassIoctlCompletion(
320 IN PDEVICE_OBJECT DeviceObject
,
328 IN PDEVICE_OBJECT DeviceObject
,
335 IN PDEVICE_OBJECT DeviceObject
,
341 CdRomCheckRegistryForMediaChangeValue(
342 IN PUNICODE_STRING RegistryPath
,
343 IN ULONG DeviceNumber
349 IN PDEVICE_EXTENSION DeviceExtension
,
350 IN PIRP IrpToComplete
,
351 IN OPTIONAL PKEVENT IoctlEvent
356 CreateCdRomDeviceObject(
357 IN PDRIVER_OBJECT DriverObject
,
358 IN PDEVICE_OBJECT PortDeviceObject
,
360 IN PULONG DeviceCount
,
361 PIO_SCSI_CAPABILITIES PortCapabilities
,
362 IN PSCSI_INQUIRY_DATA LunInfo
,
363 IN PCLASS_INIT_DATA InitializationData
,
364 IN PUNICODE_STRING RegistryPath
370 PDEVICE_OBJECT DeviceObject
,
371 PINQUIRYDATA InquiryData
,
372 PIO_SCSI_CAPABILITIES PortCapabilities
378 IN PDEVICE_OBJECT DeviceObject
384 PDEVICE_OBJECT DeviceObject
,
385 PSCSI_REQUEST_BLOCK Srb
,
390 IO_COMPLETION_ROUTINE ToshibaProcessErrorCompletion
;
394 PDEVICE_OBJECT DeviceObject
,
395 PSCSI_REQUEST_BLOCK Srb
,
402 IsThisAnAtapiChanger(
403 IN PDEVICE_OBJECT DeviceObject
,
404 OUT PULONG DiscsPresent
410 IN PDEVICE_OBJECT DeviceObject
,
417 IsThisAMultiLunDevice(
418 IN PDEVICE_OBJECT DeviceObject
,
419 IN PDEVICE_OBJECT PortDeviceObject
424 CdRomCreateNamedEvent(
425 IN PDEVICE_EXTENSION DeviceExtension
,
426 IN ULONG DeviceNumber
433 IN UNICODE_STRING ScsiUnicodeString
[],
434 OUT PUCHAR IntermediateController
439 #pragma alloc_text(PAGE, DriverEntry)
440 #pragma alloc_text(PAGE, ScsiCdRomFindDevices)
441 #pragma alloc_text(PAGE, CreateCdRomDeviceObject)
442 #pragma alloc_text(PAGE, ScanForSpecial)
443 //#pragma alloc_text(PAGE, CdRomDeviceControl)
444 #pragma alloc_text(PAGE, HitachProcessError)
445 #pragma alloc_text(PAGE, CdRomIsPlayActive)
446 #pragma alloc_text(PAGE, ScsiCdRomReadVerification)
447 #pragma alloc_text(INIT, CdRomCheckRegistryForMediaChangeValue)
448 #pragma alloc_text(INIT, IsThisAnAtapiChanger)
449 #pragma alloc_text(INIT, IsThisASanyo)
450 #pragma alloc_text(INIT, IsThisAMultiLunDevice)
451 #pragma alloc_text(INIT, CdRomCreateNamedEvent)
453 #pragma alloc_text(PAGE, FindScsiAdapter)
462 IN PDRIVER_OBJECT DriverObject
,
463 IN PUNICODE_STRING RegistryPath
470 This routine initializes the cdrom class driver.
474 DriverObject - Pointer to driver object created by system.
476 RegistryPath - Pointer to the name of the services node for this driver.
480 The function value is the final status from the initialization operation.
485 CLASS_INIT_DATA InitializationData
;
488 return STATUS_NO_SUCH_DEVICE
;
495 RtlZeroMemory (&InitializationData
, sizeof(CLASS_INIT_DATA
));
501 InitializationData
.InitializationDataSize
= sizeof(CLASS_INIT_DATA
);
502 InitializationData
.DeviceExtensionSize
= DEVICE_EXTENSION_SIZE
;
504 InitializationData
.DeviceType
= FILE_DEVICE_CD_ROM
;
505 InitializationData
.DeviceCharacteristics
= FILE_REMOVABLE_MEDIA
| FILE_READ_ONLY_DEVICE
;
511 InitializationData
.ClassReadWriteVerification
= ScsiCdRomReadVerification
;
512 InitializationData
.ClassDeviceControl
= CdRomDeviceControl
;
513 InitializationData
.ClassFindDevices
= ScsiCdRomFindDevices
;
514 InitializationData
.ClassShutdownFlush
= NULL
;
515 InitializationData
.ClassCreateClose
= NULL
;
516 InitializationData
.ClassStartIo
= ScsiCdRomStartIo
;
519 // Call the class init routine
522 return ScsiClassInitialize( DriverObject
, RegistryPath
, &InitializationData
);
524 } // end DriverEntry()
528 ScsiCdRomFindDevices(
529 IN PDRIVER_OBJECT DriverObject
,
530 IN PUNICODE_STRING RegistryPath
,
531 IN PCLASS_INIT_DATA InitializationData
,
532 IN PDEVICE_OBJECT PortDeviceObject
,
540 Connect to SCSI port driver. Get adapter capabilities and
541 SCSI bus configuration information. Search inquiry data
542 for CDROM devices to process.
546 DriverObject - CDROM class driver object.
547 PortDeviceObject - SCSI port driver device object.
548 PortNumber - The system ordinal for this scsi adapter.
552 TRUE if CDROM device present on this SCSI adapter.
557 PIO_SCSI_CAPABILITIES portCapabilities
;
560 PSCSI_INQUIRY_DATA lunInfo
;
561 PSCSI_ADAPTER_BUS_INFO adapterInfo
;
562 PINQUIRYDATA inquiryData
;
565 BOOLEAN foundDevice
= FALSE
;
568 // Call port driver to get adapter capabilities.
571 status
= ScsiClassGetCapabilities(PortDeviceObject
, &portCapabilities
);
573 if (!NT_SUCCESS(status
)) {
574 DebugPrint((1,"FindScsiDevices: ScsiClassGetCapabilities failed\n"));
579 // Call port driver to get inquiry information to find cdroms.
582 status
= ScsiClassGetInquiryData(PortDeviceObject
, (PSCSI_ADAPTER_BUS_INFO
*) &buffer
);
584 if (!NT_SUCCESS(status
)) {
585 DebugPrint((1,"FindScsiDevices: ScsiClassGetInquiryData failed\n"));
590 // Get the address of the count of the number of cdroms already initialized.
593 cdRomCount
= &IoGetConfigurationInformation()->CdRomCount
;
594 adapterInfo
= (PVOID
) buffer
;
597 // For each SCSI bus this adapter supports ...
600 for (scsiBus
=0; scsiBus
< adapterInfo
->NumberOfBuses
; scsiBus
++) {
603 // Get the SCSI bus scan data for this bus.
606 lunInfo
= (PVOID
) (buffer
+ adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
);
609 // Search list for unclaimed disk devices.
612 while (adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
) {
614 inquiryData
= (PVOID
)lunInfo
->InquiryData
;
616 if ((inquiryData
->DeviceType
== READ_ONLY_DIRECT_ACCESS_DEVICE
) &&
617 (inquiryData
->DeviceTypeQualifier
== 0) &&
618 (!lunInfo
->DeviceClaimed
)) {
620 DebugPrint((1,"FindScsiDevices: Vendor string is %.24s\n",
621 inquiryData
->VendorId
));
624 // Create device objects for cdrom
627 status
= CreateCdRomDeviceObject(DriverObject
,
636 if (NT_SUCCESS(status
)) {
639 // Increment system cdrom device count.
645 // Indicate that a cdrom device was found.
656 if (lunInfo
->NextInquiryDataOffset
== 0) {
660 lunInfo
= (PVOID
) (buffer
+ lunInfo
->NextInquiryDataOffset
);
669 } // end FindScsiCdRoms()
673 CdRomCreateNamedEvent(
674 IN PDEVICE_EXTENSION DeviceExtension
,
675 IN ULONG DeviceNumber
682 Create the named synchronization event for notification of media change
683 events to the system. The event is reset before this function returns.
687 DeviceExtension - the device extension pointer for storage of the event pointer.
696 UNICODE_STRING unicodeString
;
697 OBJECT_ATTRIBUTES objectAttributes
;
698 CCHAR eventNameBuffer
[MAXIMUM_FILENAME_LENGTH
];
699 STRING eventNameString
;
704 sprintf(eventNameBuffer
,"\\Device\\MediaChangeEvent%ld",
707 RtlInitString(&eventNameString
,
710 status
= RtlAnsiStringToUnicodeString(&unicodeString
,
714 if (!NT_SUCCESS(status
)) {
718 InitializeObjectAttributes(&objectAttributes
,
720 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
724 DeviceExtension
->MediaChangeEvent
= IoCreateSynchronizationEvent(&unicodeString
,
726 DeviceExtension
->MediaChangeEventHandle
= handle
;
728 KeClearEvent(DeviceExtension
->MediaChangeEvent
);
730 RtlFreeUnicodeString(&unicodeString
);
735 CreateCdRomDeviceObject(
736 IN PDRIVER_OBJECT DriverObject
,
737 IN PDEVICE_OBJECT PortDeviceObject
,
739 IN PULONG DeviceCount
,
740 IN PIO_SCSI_CAPABILITIES PortCapabilities
,
741 IN PSCSI_INQUIRY_DATA LunInfo
,
742 IN PCLASS_INIT_DATA InitializationData
,
743 IN PUNICODE_STRING RegistryPath
750 This routine creates an object for the device and then calls the
751 SCSI port driver for media capacity and sector size.
755 DriverObject - Pointer to driver object created by system.
756 PortDeviceObject - to connect to SCSI port driver.
757 DeviceCount - Number of previously installed CDROMs.
758 PortCapabilities - Pointer to structure returned by SCSI port
759 driver describing adapter capabilites (and limitations).
760 LunInfo - Pointer to configuration information for this device.
768 UCHAR ntNameBuffer
[64];
769 UNICODE_STRING ntUnicodeString
;
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 RtlFreeUnicodeString(&ntUnicodeString
);
819 goto CreateCdRomDeviceObjectExit
;
823 // Indicate that IRPs should include MDLs.
826 deviceObject
->Flags
|= DO_DIRECT_IO
;
829 // Set up required stack size in device object.
832 deviceObject
->StackSize
= PortDeviceObject
->StackSize
+ 2;
834 deviceExtension
= deviceObject
->DeviceExtension
;
837 // Allocate spinlock for split request completion.
840 KeInitializeSpinLock(&deviceExtension
->SplitRequestSpinLock
);
843 // This is the physical device.
846 deviceExtension
->PhysicalDevice
= deviceObject
;
849 // Initialize lock count to zero. The lock count is used to
850 // disable the ejection mechanism when media is mounted.
853 deviceExtension
->LockCount
= 0;
856 // Save system cdrom number
859 deviceExtension
->DeviceNumber
= *DeviceCount
;
862 // Copy port device object to device extension.
865 deviceExtension
->PortDeviceObject
= PortDeviceObject
;
868 // Set the alignment requirements for the device based on the
869 // host adapter requirements
872 if (PortDeviceObject
->AlignmentRequirement
> deviceObject
->AlignmentRequirement
) {
873 deviceObject
->AlignmentRequirement
= PortDeviceObject
->AlignmentRequirement
;
877 // Save address of port driver capabilities.
880 deviceExtension
->PortCapabilities
= PortCapabilities
;
886 deviceExtension
->SrbFlags
= 0;
887 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
890 // Allocate request sense buffer.
893 senseData
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
895 if (senseData
== NULL
) {
898 // The buffer cannot be allocated.
901 status
= STATUS_INSUFFICIENT_RESOURCES
;
902 goto CreateCdRomDeviceObjectExit
;
906 // Set the sense data pointer in the device extension.
909 deviceExtension
->SenseData
= senseData
;
912 // CDROMs are not partitionable so starting offset is 0.
915 deviceExtension
->StartingOffset
.LowPart
= 0;
916 deviceExtension
->StartingOffset
.HighPart
= 0;
919 // Path/TargetId/LUN describes a device location on the SCSI bus.
920 // This information comes from the LunInfo buffer.
923 deviceExtension
->PortNumber
= (UCHAR
)PortNumber
;
924 deviceExtension
->PathId
= LunInfo
->PathId
;
925 deviceExtension
->TargetId
= LunInfo
->TargetId
;
926 deviceExtension
->Lun
= LunInfo
->Lun
;
929 // Set timeout value in seconds.
932 timeOut
= ScsiClassQueryTimeOutRegistryValue(RegistryPath
);
934 deviceExtension
->TimeOutValue
= timeOut
;
936 deviceExtension
->TimeOutValue
= SCSI_CDROM_TIMEOUT
;
940 // Build the lookaside list for srb's for the physical disk. Should only
944 ScsiClassInitializeSrbLookasideList(deviceExtension
,
945 CDROM_SRB_LIST_SIZE
);
947 srbListInitialized
= TRUE
;
950 // Back pointer to device object.
953 deviceExtension
->DeviceObject
= deviceObject
;
956 // Allocate buffer for drive geometry.
959 deviceExtension
->DiskGeometry
=
960 ExAllocatePool(NonPagedPool
, sizeof(DISK_GEOMETRY
));
962 if (deviceExtension
->DiskGeometry
== NULL
) {
964 status
= STATUS_INSUFFICIENT_RESOURCES
;
965 goto CreateCdRomDeviceObjectExit
;
969 // Set up media change support defaults.
972 cddata
= (PCDROM_DATA
)(deviceExtension
+ 1);
974 KeInitializeSpinLock(&cddata
->FormSpinLock
);
975 KeInitializeSpinLock(&cddata
->TimerIrpSpinLock
);
976 InitializeListHead(&cddata
->TimerIrpList
);
978 cddata
->MediaChangeCountDown
= MEDIA_CHANGE_DEFAULT_TIME
;
979 cddata
->MediaChangeSupported
= FALSE
;
980 cddata
->MediaChange
= FALSE
;
983 // Assume that there is initially no media in the device
984 // only notify upper layers if there is something there
987 deviceExtension
->MediaChangeNoMedia
= TRUE
;
988 cddata
->MediaChangeIrp
= NULL
;
990 cddata
->MediaChangeIrpTimeInUse
= 0;
991 cddata
->MediaChangeIrpLost
= FALSE
;
995 // Scan for Scsi controllers that require special processing.
998 ScanForSpecial(deviceObject
,
999 (PINQUIRYDATA
) LunInfo
->InquiryData
,
1003 // Do READ CAPACITY. This SCSI command
1004 // returns the last sector address on the device
1005 // and the bytes per sector.
1006 // These are used to calculate the drive capacity
1010 status
= ScsiClassReadDriveCapacity(deviceObject
);
1011 bps
= deviceExtension
->DiskGeometry
->BytesPerSector
;
1013 if (!NT_SUCCESS(status
) || !bps
) {
1016 "CreateCdRomDeviceObjects: Can't read capacity for device %s\n",
1020 // Set disk geometry to default values (per ISO 9660).
1024 deviceExtension
->SectorShift
= 11;
1025 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(0x7fffffff);
1029 // Insure that bytes per sector is a power of 2
1030 // This corrects a problem with the HP 4020i CDR where it
1031 // returns an incorrect number for bytes per sector.
1034 lastBit
= (ULONG
) -1;
1042 deviceExtension
->DiskGeometry
->BytesPerSector
= bps
;
1043 DebugPrint((2, "CreateCdRomDeviceObject: Calc'd bps = %x\n", bps
));
1046 // Check to see if this is some sort of changer device
1049 changerDevice
= FALSE
;
1052 // Search for devices that have special requirements for media
1056 if (deviceExtension
->Lun
> 0) {
1057 changerDevice
= TRUE
;
1060 if (!changerDevice
) {
1061 changerDevice
= IsThisASanyo(deviceObject
, deviceExtension
->PathId
,
1062 deviceExtension
->TargetId
);
1065 if (!changerDevice
) {
1067 changerDevice
= IsThisAnAtapiChanger(deviceObject
, &tmp
);
1070 if (!changerDevice
) {
1071 changerDevice
= IsThisAMultiLunDevice(deviceObject
, PortDeviceObject
);
1075 // If it is a changer device, increment the timeout to take platter-swapping
1076 // time into account
1080 deviceExtension
->TimeOutValue
+= SCSI_CHANGER_BONUS_TIMEOUT
;
1084 // Create the media change named event. If this succeeds then continue
1085 // initializing the media change support data items.
1088 CdRomCreateNamedEvent(deviceExtension
,*DeviceCount
);
1089 if (deviceExtension
->MediaChangeEvent
) {
1092 // If this is not a changer, get an IRP for the timer request
1093 // and initialize the timer.
1096 if (!changerDevice
) {
1099 // Not a changer device - continue with media change initialization.
1100 // Determine if the user actually wants media change events.
1103 if (CdRomCheckRegistryForMediaChangeValue(RegistryPath
, *DeviceCount
)) {
1104 PIO_STACK_LOCATION irpStack
;
1105 PSCSI_REQUEST_BLOCK srb
;
1109 // User wants it - preallocate IRP and SRB.
1112 irp
= IoAllocateIrp((CCHAR
)(deviceObject
->StackSize
+1),
1117 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
1118 buffer
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
1120 if (srb
&& buffer
) {
1124 // All resources have been allocated set up the IRP.
1127 IoSetNextIrpStackLocation(irp
);
1128 irpStack
= IoGetCurrentIrpStackLocation(irp
);
1129 irpStack
->DeviceObject
= deviceObject
;
1130 irpStack
= IoGetNextIrpStackLocation(irp
);
1131 cddata
->MediaChangeIrp
= irp
;
1132 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1135 // Initialize the SRB
1138 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
1141 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
* 2;
1142 srb
->QueueTag
= SP_UNTAGGED
;
1143 srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
1144 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1145 srb
->PathId
= deviceExtension
->PathId
;
1146 srb
->TargetId
= deviceExtension
->TargetId
;
1147 srb
->Lun
= deviceExtension
->Lun
;
1148 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1151 // Initialize and set up the sense information buffer
1154 RtlZeroMemory(buffer
, SENSE_BUFFER_SIZE
);
1155 srb
->SenseInfoBuffer
= buffer
;
1156 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1159 // Initialize the CDB
1162 cdb
= (PCDB
)&srb
->Cdb
[0];
1163 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_TEST_UNIT_READY
;
1164 cdb
->CDB6GENERIC
.LogicalUnitNumber
= deviceExtension
->Lun
;
1167 // It is ok to support media change events on this device.
1170 cddata
->MediaChangeSupported
= TRUE
;
1171 cddata
->MediaChange
= TRUE
;
1185 deviceExtension
->MediaChangeEvent
= NULL
;
1188 deviceExtension
->MediaChangeEvent
= NULL
;
1193 // Assume use of 6-byte mode sense/select for now.
1196 cddata
->XAFlags
|= XA_USE_6_BYTE
;
1199 // Build and issue mode sense with Read error recovery page. This will be used to change
1200 // block size in case of any raw reads (Mode 2, Form 2).
1203 length
= (sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH
);
1205 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
1208 cdb
= (PCDB
)srb
.Cdb
;
1211 // Set timeout value from device extension.
1214 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
1217 // Build the MODE SENSE CDB. The data returned will be kept in the device extension
1218 // and used to set block size.
1221 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
1222 cdb
->MODE_SENSE
.PageCode
= 0x1;
1223 cdb
->MODE_SENSE
.AllocationLength
= (UCHAR
)length
;
1225 buffer
= ExAllocatePool(NonPagedPoolCacheAligned
, (sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH10
));
1227 status
= STATUS_INSUFFICIENT_RESOURCES
;
1228 goto CreateCdRomDeviceObjectExit
;
1231 status
= ScsiClassSendSrbSynchronous(deviceObject
,
1236 if (!NT_SUCCESS(status
)) {
1239 // May be Atapi, try 10-byte.
1242 length
= (sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH10
);
1244 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
1247 // Build the MODE SENSE CDB.
1251 cdb
= (PCDB
)srb
.Cdb
;
1254 // Set timeout value from device extension.
1257 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
1259 cdb
->MODE_SENSE10
.OperationCode
= SCSIOP_MODE_SENSE10
;
1260 cdb
->MODE_SENSE10
.PageCode
= 0x1;
1262 cdb
->MODE_SENSE10
.AllocationLength
[0] = (UCHAR
)(length
>> 8);
1263 cdb
->MODE_SENSE10
.AllocationLength
[1] = (UCHAR
)(length
& 0xFF);
1265 status
= ScsiClassSendSrbSynchronous(deviceObject
,
1270 if (status
== STATUS_DATA_OVERRUN
) {
1273 // Build and issue the ReadCd command to ensure that this device supports it.
1276 RtlZeroMemory(cdb
, 12);
1278 cdb
->READ_CD
.OperationCode
= SCSIOP_READ_CD
;
1280 status
= ScsiClassSendSrbSynchronous(deviceObject
,
1287 // If the command wasn't rejected then support the READ_CD.
1290 if (NT_SUCCESS(status
) || (status
== STATUS_NO_MEDIA_IN_DEVICE
)) {
1293 // Using Read CD precludes issueing a mode select to
1294 // set the user data size. So, no buffer copy is
1298 cddata
->XAFlags
&= ~XA_USE_6_BYTE
;
1299 cddata
->XAFlags
= XA_USE_READ_CD
| XA_USE_10_BYTE
;
1302 RtlCopyMemory(&cddata
->u1
.Header
, buffer
, sizeof(ERROR_RECOVERY_DATA10
));
1303 cddata
->u1
.Header
.ModeDataLength
= 0;
1305 cddata
->XAFlags
&= ~XA_USE_6_BYTE
;
1306 cddata
->XAFlags
|= XA_USE_10_BYTE
;
1309 } else if (NT_SUCCESS(status
)) {
1311 RtlCopyMemory(&cddata
->u1
.Header
, buffer
, sizeof(ERROR_RECOVERY_DATA10
));
1312 cddata
->u1
.Header
.ModeDataLength
= 0;
1314 cddata
->XAFlags
&= ~XA_USE_6_BYTE
;
1315 cddata
->XAFlags
|= XA_USE_10_BYTE
;
1318 cddata
->XAFlags
|= XA_NOT_SUPPORTED
;
1321 RtlCopyMemory(&cddata
->u1
.Header
, buffer
, sizeof(ERROR_RECOVERY_DATA
));
1322 cddata
->u1
.Header
.ModeDataLength
= 0;
1328 // Start the timer now regardless of if Autorun is enabled.
1329 // The timer must run forever since IoStopTimer faults.
1332 IoInitializeTimer(deviceObject
, CdRomTickHandler
, NULL
);
1333 IoStartTimer(deviceObject
);
1335 return(STATUS_SUCCESS
);
1337 CreateCdRomDeviceObjectExit
:
1340 // Release the device since an error occured.
1343 ScsiClassClaimDevice(PortDeviceObject
,
1348 if (senseData
!= NULL
) {
1349 ExFreePool(senseData
);
1352 if (deviceExtension
->DiskGeometry
!= NULL
) {
1353 ExFreePool(deviceExtension
->DiskGeometry
);
1356 if (deviceObject
!= NULL
) {
1357 if (srbListInitialized
) {
1358 ExDeleteNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
);
1360 IoDeleteDevice(deviceObject
);
1366 } // end CreateCdRomDeviceObject()
1371 IN PDEVICE_OBJECT DeviceObject
,
1376 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1377 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1378 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
1379 PIO_STACK_LOCATION irpStack
;
1381 ULONG transferPages
;
1382 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
1383 ULONG maximumTransferLength
= deviceExtension
->PortCapabilities
->MaximumTransferLength
;
1385 PSCSI_REQUEST_BLOCK srb
= NULL
;
1387 PUCHAR senseBuffer
= NULL
;
1393 // Mark IRP with status pending.
1396 IoMarkIrpPending(Irp
);
1399 // If the flag is set in the device object, force a verify.
1402 if (DeviceObject
->Flags
& DO_VERIFY_VOLUME
) {
1403 DebugPrint((2, "ScsiCdRomStartIo: [%lx] Volume needs verified\n", Irp
));
1404 if (!(currentIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
)) {
1406 if (Irp
->Tail
.Overlay
.Thread
) {
1407 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
1410 Irp
->IoStatus
.Status
= STATUS_VERIFY_REQUIRED
;
1412 DebugPrint((2, "ScsiCdRomStartIo: [%lx] Calling UpdateCapcity - "
1413 "ioctl event = %lx\n",
1415 nextIrpStack
->Parameters
.Others
.Argument1
1419 // our device control dispatch routine stores an event in the next
1420 // stack location to signal when startio has completed. We need to
1421 // pass this in so that the update capacity completion routine can
1422 // set it rather than completing the Irp.
1425 status
= CdRomUpdateCapacity(deviceExtension
,
1427 nextIrpStack
->Parameters
.Others
.Argument1
1430 DebugPrint((2, "ScsiCdRomStartIo: [%lx] UpdateCapacity returned %lx\n", Irp
, status
));
1431 ASSERT(status
== STATUS_PENDING
);
1436 cdData
= (PCDROM_DATA
)(deviceExtension
+ 1);
1437 use6Byte
= cdData
->XAFlags
& XA_USE_6_BYTE
;
1439 if (currentIrpStack
->MajorFunction
== IRP_MJ_READ
) {
1442 // Add partition byte offset to make starting byte relative to
1443 // beginning of disk. In addition, add in skew for DM Driver, if any.
1446 currentIrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+= (deviceExtension
->StartingOffset
.QuadPart
);
1449 // Calculate number of pages in this transfer.
1452 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp
->MdlAddress
),
1453 currentIrpStack
->Parameters
.Read
.Length
);
1456 // Check if request length is greater than the maximum number of
1457 // bytes that the hardware can transfer.
1460 if (cdData
->RawAccess
) {
1462 ASSERT(!(cdData
->XAFlags
& XA_USE_READ_CD
));
1465 // Fire off a mode select to switch back to cooked sectors.
1468 irp2
= IoAllocateIrp((CCHAR
)(deviceExtension
->DeviceObject
->StackSize
+1),
1472 Irp
->IoStatus
.Information
= 0;
1473 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1474 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1475 IoStartNextPacket(DeviceObject
, FALSE
);
1479 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
1481 Irp
->IoStatus
.Information
= 0;
1482 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1483 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1485 IoStartNextPacket(DeviceObject
, FALSE
);
1489 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
1491 cdb
= (PCDB
)srb
->Cdb
;
1494 // Allocate sense buffer.
1497 senseBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
1500 Irp
->IoStatus
.Information
= 0;
1501 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1502 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1505 IoStartNextPacket(DeviceObject
, FALSE
);
1513 IoSetNextIrpStackLocation(irp2
);
1514 irp2
->IoStatus
.Status
= STATUS_SUCCESS
;
1515 irp2
->IoStatus
.Information
= 0;
1517 irp2
->UserBuffer
= NULL
;
1520 // Save the device object and irp in a private stack location.
1523 irpStack
= IoGetCurrentIrpStackLocation(irp2
);
1524 irpStack
->DeviceObject
= deviceExtension
->DeviceObject
;
1525 irpStack
->Parameters
.Others
.Argument2
= (PVOID
) Irp
;
1528 // The retry count will be in the real Irp, as the retry logic will
1529 // recreate our private irp.
1532 if (!(nextIrpStack
->Parameters
.Others
.Argument1
)) {
1535 // Only jam this in if it doesn't exist. The completion routines can
1536 // call StartIo directly in the case of retries and resetting it will
1537 // cause infinite loops.
1540 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
1544 // Construct the IRP stack for the lower level driver.
1547 irpStack
= IoGetNextIrpStackLocation(irp2
);
1548 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
1549 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
1550 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1552 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1553 srb
->PathId
= deviceExtension
->PathId
;
1554 srb
->TargetId
= deviceExtension
->TargetId
;
1555 srb
->Lun
= deviceExtension
->Lun
;
1556 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1557 srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
1558 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
1560 srb
->OriginalRequest
= irp2
;
1561 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1562 srb
->SenseInfoBuffer
= senseBuffer
;
1564 transferByteCount
= (use6Byte
) ? sizeof(ERROR_RECOVERY_DATA
) : sizeof(ERROR_RECOVERY_DATA10
);
1565 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, transferByteCount
);
1567 Irp
->IoStatus
.Information
= 0;
1568 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1569 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1570 ExFreePool(senseBuffer
);
1573 IoStartNextPacket(DeviceObject
, FALSE
);
1578 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
1584 if (!irp2
->MdlAddress
) {
1585 Irp
->IoStatus
.Information
= 0;
1586 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1587 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1588 ExFreePool(senseBuffer
);
1590 ExFreePool(dataBuffer
);
1592 IoStartNextPacket(DeviceObject
, FALSE
);
1600 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
1602 srb
->DataBuffer
= dataBuffer
;
1605 // Set the new block size in the descriptor.
1608 cdData
->u1
.BlockDescriptor
.BlockLength
[0] = (UCHAR
)(COOKED_SECTOR_SIZE
>> 16) & 0xFF;
1609 cdData
->u1
.BlockDescriptor
.BlockLength
[1] = (UCHAR
)(COOKED_SECTOR_SIZE
>> 8) & 0xFF;
1610 cdData
->u1
.BlockDescriptor
.BlockLength
[2] = (UCHAR
)(COOKED_SECTOR_SIZE
& 0xFF);
1613 // Move error page into dataBuffer.
1616 RtlCopyMemory(srb
->DataBuffer
, &cdData
->u1
.Header
, transferByteCount
);
1619 // Build and send a mode select to switch into raw mode.
1622 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
1623 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_OUT
);
1624 srb
->DataTransferLength
= transferByteCount
;
1625 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
* 2;
1629 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
1630 cdb
->MODE_SELECT
.PFBit
= 1;
1631 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)transferByteCount
;
1634 srb
->CdbLength
= 10;
1635 cdb
->MODE_SELECT10
.OperationCode
= SCSIOP_MODE_SELECT10
;
1636 cdb
->MODE_SELECT10
.PFBit
= 1;
1637 cdb
->MODE_SELECT10
.ParameterListLength
[0] = (UCHAR
)(transferByteCount
>> 8);
1638 cdb
->MODE_SELECT10
.ParameterListLength
[1] = (UCHAR
)(transferByteCount
& 0xFF);
1642 // Update completion routine.
1645 IoSetCompletionRoutine(irp2
,
1646 CdRomSwitchModeCompletion
,
1652 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
1656 if ((currentIrpStack
->Parameters
.Read
.Length
> maximumTransferLength
) ||
1658 deviceExtension
->PortCapabilities
->MaximumPhysicalPages
)) {
1661 // Request needs to be split. Completion of each portion of the
1662 // request will fire off the next portion. The final request will
1663 // signal Io to send a new request.
1667 deviceExtension
->PortCapabilities
->MaximumPhysicalPages
- 1;
1669 if(maximumTransferLength
> transferPages
<< PAGE_SHIFT
) {
1670 maximumTransferLength
= transferPages
<< PAGE_SHIFT
;
1674 // Check that the maximum transfer size is not zero
1677 if(maximumTransferLength
== 0) {
1678 maximumTransferLength
= PAGE_SIZE
;
1681 ScsiClassSplitRequest(DeviceObject
, Irp
, maximumTransferLength
);
1687 // Build SRB and CDB for this IRP.
1690 ScsiClassBuildRequest(DeviceObject
, Irp
);
1695 } else if (currentIrpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
) {
1698 // Allocate an irp, srb and associated structures.
1701 irp2
= IoAllocateIrp((CCHAR
)(deviceExtension
->DeviceObject
->StackSize
+1),
1705 Irp
->IoStatus
.Information
= 0;
1706 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1707 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1708 IoStartNextPacket(DeviceObject
, FALSE
);
1709 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp
, Irp
->IoStatus
.Status
, __LINE__
));
1713 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
1715 Irp
->IoStatus
.Information
= 0;
1716 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1717 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1719 IoStartNextPacket(DeviceObject
, FALSE
);
1720 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp
, Irp
->IoStatus
.Status
, __LINE__
));
1724 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
1726 cdb
= (PCDB
)srb
->Cdb
;
1729 // Allocate sense buffer.
1732 senseBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
1735 Irp
->IoStatus
.Information
= 0;
1736 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1737 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1740 IoStartNextPacket(DeviceObject
, FALSE
);
1741 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp
, Irp
->IoStatus
.Status
, __LINE__
));
1749 IoSetNextIrpStackLocation(irp2
);
1750 irp2
->IoStatus
.Status
= STATUS_SUCCESS
;
1751 irp2
->IoStatus
.Information
= 0;
1753 irp2
->UserBuffer
= NULL
;
1756 // Save the device object and irp in a private stack location.
1759 irpStack
= IoGetCurrentIrpStackLocation(irp2
);
1760 irpStack
->DeviceObject
= deviceExtension
->DeviceObject
;
1761 irpStack
->Parameters
.Others
.Argument2
= (PVOID
) Irp
;
1764 // The retry count will be in the real Irp, as the retry logic will
1765 // recreate our private irp.
1768 if (!(nextIrpStack
->Parameters
.Others
.Argument1
)) {
1771 // Only jam this in if it doesn't exist. The completion routines can
1772 // call StartIo directly in the case of retries and resetting it will
1773 // cause infinite loops.
1776 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
1780 // Construct the IRP stack for the lower level driver.
1783 irpStack
= IoGetNextIrpStackLocation(irp2
);
1784 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
1785 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
1786 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1788 IoSetCompletionRoutine(irp2
,
1789 CdRomDeviceControlCompletion
,
1795 // Setup those fields that are generic to all requests.
1798 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1799 srb
->PathId
= deviceExtension
->PathId
;
1800 srb
->TargetId
= deviceExtension
->TargetId
;
1801 srb
->Lun
= deviceExtension
->Lun
;
1802 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1803 srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
1804 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
1806 srb
->OriginalRequest
= irp2
;
1807 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1808 srb
->SenseInfoBuffer
= senseBuffer
;
1810 switch (currentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
) {
1812 case IOCTL_CDROM_RAW_READ
: {
1815 // Determine whether the drive is currently in raw or cooked mode,
1816 // and which command to use to read the data.
1819 if (!(cdData
->XAFlags
& XA_USE_READ_CD
)) {
1821 PRAW_READ_INFO rawReadInfo
=
1822 (PRAW_READ_INFO
)currentIrpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
1823 ULONG maximumTransferLength
;
1824 ULONG transferPages
;
1826 if (cdData
->RawAccess
) {
1828 ULONG startingSector
;
1831 // Free the recently allocated irp, as we don't need it.
1836 cdb
= (PCDB
)srb
->Cdb
;
1837 RtlZeroMemory(cdb
, 12);
1840 // Calculate starting offset.
1843 startingSector
= (ULONG
)(rawReadInfo
->DiskOffset
.QuadPart
>> deviceExtension
->SectorShift
);
1844 transferByteCount
= rawReadInfo
->SectorCount
* RAW_SECTOR_SIZE
;
1845 maximumTransferLength
= deviceExtension
->PortCapabilities
->MaximumTransferLength
;
1846 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp
->MdlAddress
),
1850 // Determine if request is within limits imposed by miniport.
1853 if (transferByteCount
> maximumTransferLength
||
1854 transferPages
> deviceExtension
->PortCapabilities
->MaximumPhysicalPages
) {
1857 // The claim is that this won't happen, and is backed up by
1858 // ActiveMovie usage, which does unbuffered XA reads of 0x18000, yet
1859 // we get only 4 sector requests.
1863 Irp
->IoStatus
.Information
= 0;
1864 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
1865 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1866 ExFreePool(senseBuffer
);
1868 IoStartNextPacket(DeviceObject
, FALSE
);
1873 srb
->OriginalRequest
= Irp
;
1874 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
1875 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
1876 srb
->DataTransferLength
= transferByteCount
;
1877 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
1878 srb
->CdbLength
= 10;
1879 srb
->DataBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
1881 if (rawReadInfo
->TrackMode
== CDDA
) {
1882 if (cdData
->XAFlags
& PLEXTOR_CDDA
) {
1884 srb
->CdbLength
= 12;
1886 cdb
->PLXTR_READ_CDDA
.LogicalUnitNumber
= deviceExtension
->Lun
;
1887 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
1888 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
1889 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
1890 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
1892 cdb
->PLXTR_READ_CDDA
.TransferBlockByte3
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
1893 cdb
->PLXTR_READ_CDDA
.TransferBlockByte2
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
1894 cdb
->PLXTR_READ_CDDA
.TransferBlockByte1
= 0;
1895 cdb
->PLXTR_READ_CDDA
.TransferBlockByte0
= 0;
1897 cdb
->PLXTR_READ_CDDA
.SubCode
= 0;
1898 cdb
->PLXTR_READ_CDDA
.OperationCode
= 0xD8;
1900 } else if (cdData
->XAFlags
& NEC_CDDA
) {
1902 cdb
->NEC_READ_CDDA
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
1903 cdb
->NEC_READ_CDDA
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
1904 cdb
->NEC_READ_CDDA
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
1905 cdb
->NEC_READ_CDDA
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
1907 cdb
->NEC_READ_CDDA
.TransferBlockByte1
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
1908 cdb
->NEC_READ_CDDA
.TransferBlockByte0
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
1910 cdb
->NEC_READ_CDDA
.OperationCode
= 0xD4;
1914 cdb
->CDB10
.LogicalUnitNumber
= deviceExtension
->Lun
;
1916 cdb
->CDB10
.TransferBlocksMsb
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
1917 cdb
->CDB10
.TransferBlocksLsb
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
1919 cdb
->CDB10
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
1920 cdb
->CDB10
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
1921 cdb
->CDB10
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
1922 cdb
->CDB10
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
1924 cdb
->CDB10
.OperationCode
= SCSIOP_READ
;
1927 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
1929 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
1930 nextIrpStack
->Parameters
.Scsi
.Srb
= srb
;
1932 if (!(nextIrpStack
->Parameters
.Others
.Argument1
)) {
1935 // Only jam this in if it doesn't exist. The completion routines can
1936 // call StartIo directly in the case of retries and resetting it will
1937 // cause infinite loops.
1940 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
1944 // Set up IoCompletion routine address.
1947 IoSetCompletionRoutine(Irp
,
1954 IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
1959 transferByteCount
= (use6Byte
) ? sizeof(ERROR_RECOVERY_DATA
) : sizeof(ERROR_RECOVERY_DATA10
);
1960 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, transferByteCount
);
1962 Irp
->IoStatus
.Information
= 0;
1963 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1964 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1965 ExFreePool(senseBuffer
);
1968 IoStartNextPacket(DeviceObject
, FALSE
);
1973 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
1979 if (!irp2
->MdlAddress
) {
1980 Irp
->IoStatus
.Information
= 0;
1981 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1982 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1983 ExFreePool(senseBuffer
);
1985 ExFreePool(dataBuffer
);
1987 IoStartNextPacket(DeviceObject
, FALSE
);
1995 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
1997 srb
->DataBuffer
= dataBuffer
;
2000 // Set the new block size in the descriptor.
2003 cdData
->u1
.BlockDescriptor
.BlockLength
[0] = (UCHAR
)(RAW_SECTOR_SIZE
>> 16) & 0xFF;
2004 cdData
->u1
.BlockDescriptor
.BlockLength
[1] = (UCHAR
)(RAW_SECTOR_SIZE
>> 8) & 0xFF;
2005 cdData
->u1
.BlockDescriptor
.BlockLength
[2] = (UCHAR
)(RAW_SECTOR_SIZE
& 0xFF);
2009 // TODO: Set density code, based on operation
2012 cdData
->u1
.BlockDescriptor
.DensityCode
= 0;
2016 // Move error page into dataBuffer.
2019 RtlCopyMemory(srb
->DataBuffer
, &cdData
->u1
.Header
, transferByteCount
);
2023 // Build and send a mode select to switch into raw mode.
2026 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2027 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_OUT
);
2028 srb
->DataTransferLength
= transferByteCount
;
2029 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
* 2;
2033 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
2034 cdb
->MODE_SELECT
.PFBit
= 1;
2035 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)transferByteCount
;
2038 srb
->CdbLength
= 10;
2039 cdb
->MODE_SELECT10
.OperationCode
= SCSIOP_MODE_SELECT10
;
2040 cdb
->MODE_SELECT10
.PFBit
= 1;
2041 cdb
->MODE_SELECT10
.ParameterListLength
[0] = (UCHAR
)(transferByteCount
>> 8);
2042 cdb
->MODE_SELECT10
.ParameterListLength
[1] = (UCHAR
)(transferByteCount
& 0xFF);
2046 // Update completion routine.
2049 IoSetCompletionRoutine(irp2
,
2050 CdRomSwitchModeCompletion
,
2060 PRAW_READ_INFO rawReadInfo
=
2061 (PRAW_READ_INFO
)currentIrpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
2062 ULONG startingSector
;
2065 // Free the recently allocated irp, as we don't need it.
2070 cdb
= (PCDB
)srb
->Cdb
;
2071 RtlZeroMemory(cdb
, 12);
2075 // Calculate starting offset.
2078 startingSector
= (ULONG
)(rawReadInfo
->DiskOffset
.QuadPart
>> deviceExtension
->SectorShift
);
2079 transferByteCount
= rawReadInfo
->SectorCount
* RAW_SECTOR_SIZE
;
2082 srb
->OriginalRequest
= Irp
;
2083 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2084 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
2085 srb
->DataTransferLength
= transferByteCount
;
2086 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2087 srb
->DataBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
2088 srb
->CdbLength
= 12;
2089 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
2092 // Fill in CDB fields.
2095 cdb
= (PCDB
)srb
->Cdb
;
2098 cdb
->READ_CD
.TransferBlocks
[2] = (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
2099 cdb
->READ_CD
.TransferBlocks
[1] = (UCHAR
) (rawReadInfo
->SectorCount
>> 8 );
2100 cdb
->READ_CD
.TransferBlocks
[0] = (UCHAR
) (rawReadInfo
->SectorCount
>> 16);
2103 cdb
->READ_CD
.StartingLBA
[3] = (UCHAR
) (startingSector
& 0xFF);
2104 cdb
->READ_CD
.StartingLBA
[2] = (UCHAR
) ((startingSector
>> 8));
2105 cdb
->READ_CD
.StartingLBA
[1] = (UCHAR
) ((startingSector
>> 16));
2106 cdb
->READ_CD
.StartingLBA
[0] = (UCHAR
) ((startingSector
>> 24));
2109 // Setup cdb depending upon the sector type we want.
2112 switch (rawReadInfo
->TrackMode
) {
2115 cdb
->READ_CD
.ExpectedSectorType
= CD_DA_SECTOR
;
2116 cdb
->READ_CD
.IncludeUserData
= 1;
2117 cdb
->READ_CD
.HeaderCode
= 3;
2118 cdb
->READ_CD
.IncludeSyncData
= 1;
2123 cdb
->READ_CD
.ExpectedSectorType
= YELLOW_MODE2_SECTOR
;
2124 cdb
->READ_CD
.IncludeUserData
= 1;
2125 cdb
->READ_CD
.HeaderCode
= 1;
2126 cdb
->READ_CD
.IncludeSyncData
= 1;
2131 cdb
->READ_CD
.ExpectedSectorType
= FORM2_MODE2_SECTOR
;
2132 cdb
->READ_CD
.IncludeUserData
= 1;
2133 cdb
->READ_CD
.HeaderCode
= 3;
2134 cdb
->READ_CD
.IncludeSyncData
= 1;
2138 Irp
->IoStatus
.Information
= 0;
2139 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
2140 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2141 ExFreePool(senseBuffer
);
2144 IoStartNextPacket(DeviceObject
, FALSE
);
2145 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp
, Irp
->IoStatus
.Status
, __LINE__
));
2149 cdb
->READ_CD
.OperationCode
= SCSIOP_READ_CD
;
2151 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
2152 nextIrpStack
->Parameters
.Scsi
.Srb
= srb
;
2154 if (!(nextIrpStack
->Parameters
.Others
.Argument1
)) {
2157 // Only jam this in if it doesn't exist. The completion routines can
2158 // call StartIo directly in the case of retries and resetting it will
2159 // cause infinite loops.
2162 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
2166 // Set up IoCompletion routine address.
2169 IoSetCompletionRoutine(Irp
,
2176 IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
2181 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2185 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
: {
2188 // Issue ReadCapacity to update device extension
2189 // with information for current media.
2193 "CdRomStartIo: Get drive capacity\n"));
2196 // setup remaining srb and cdb parameters.
2199 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2200 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
2201 srb
->DataTransferLength
= sizeof(READ_CAPACITY_DATA
);
2202 srb
->CdbLength
= 10;
2203 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2205 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, sizeof(READ_CAPACITY_DATA
));
2207 Irp
->IoStatus
.Information
= 0;
2208 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2209 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2210 ExFreePool(senseBuffer
);
2213 IoStartNextPacket(DeviceObject
, FALSE
);
2214 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp
, Irp
->IoStatus
.Status
, __LINE__
));
2219 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2220 sizeof(READ_CAPACITY_DATA
),
2225 if (!irp2
->MdlAddress
) {
2226 Irp
->IoStatus
.Information
= 0;
2227 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2228 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2229 ExFreePool(senseBuffer
);
2231 ExFreePool(dataBuffer
);
2233 IoStartNextPacket(DeviceObject
, FALSE
);
2234 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp
, Irp
->IoStatus
.Status
, __LINE__
));
2242 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2244 srb
->DataBuffer
= dataBuffer
;
2245 cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
2247 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2251 case IOCTL_CDROM_CHECK_VERIFY
: {
2254 // Since a test unit ready is about to be performed, reset the timer
2255 // value to decrease the opportunities for it to race with this code.
2258 cdData
->MediaChangeCountDown
= MEDIA_CHANGE_DEFAULT_TIME
;
2261 // Set up the SRB/CDB
2265 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_TEST_UNIT_READY
;
2266 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
* 2;
2267 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2268 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_NO_DATA_TRANSFER
);
2270 DebugPrint((2, "ScsiCdRomStartIo: [%lx] Sending CHECK_VERIFY irp %lx\n", Irp
, irp2
));
2271 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2275 case IOCTL_CDROM_GET_LAST_SESSION
:
2278 // Set format to return first and last session numbers.
2281 cdb
->READ_TOC
.Format
= GET_LAST_SESSION
;
2284 // Fall through to READ TOC code.
2287 case IOCTL_CDROM_READ_TOC
: {
2290 if (currentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_READ_TOC
) {
2293 // Use MSF addressing if not request for session information.
2296 cdb
->READ_TOC
.Msf
= CDB_USE_MSF
;
2300 // Set size of TOC structure.
2304 currentIrpStack
->Parameters
.Read
.Length
>
2305 sizeof(CDROM_TOC
) ? sizeof(CDROM_TOC
):
2306 currentIrpStack
->Parameters
.Read
.Length
;
2308 cdb
->READ_TOC
.AllocationLength
[0] = (UCHAR
) (transferByteCount
>> 8);
2309 cdb
->READ_TOC
.AllocationLength
[1] = (UCHAR
) (transferByteCount
& 0xFF);
2311 cdb
->READ_TOC
.Control
= 0;
2314 // Start at beginning of disc.
2317 cdb
->READ_TOC
.StartingTrack
= 0;
2320 // setup remaining srb and cdb parameters.
2323 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2324 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
2325 srb
->DataTransferLength
= transferByteCount
;
2326 srb
->CdbLength
= 10;
2327 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2329 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, transferByteCount
);
2331 Irp
->IoStatus
.Information
= 0;
2332 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2333 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2334 ExFreePool(senseBuffer
);
2337 IoStartNextPacket(DeviceObject
, FALSE
);
2342 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2348 if (!irp2
->MdlAddress
) {
2349 Irp
->IoStatus
.Information
= 0;
2350 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2351 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2352 ExFreePool(senseBuffer
);
2354 ExFreePool(dataBuffer
);
2356 IoStartNextPacket(DeviceObject
, FALSE
);
2364 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2366 srb
->DataBuffer
= dataBuffer
;
2367 cdb
->READ_TOC
.OperationCode
= SCSIOP_READ_TOC
;
2369 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2374 case IOCTL_CDROM_PLAY_AUDIO_MSF
: {
2376 PCDROM_PLAY_AUDIO_MSF inputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
2379 // Set up the SRB/CDB
2382 srb
->CdbLength
= 10;
2383 cdb
->PLAY_AUDIO_MSF
.OperationCode
= SCSIOP_PLAY_AUDIO_MSF
;
2385 cdb
->PLAY_AUDIO_MSF
.StartingM
= inputBuffer
->StartingM
;
2386 cdb
->PLAY_AUDIO_MSF
.StartingS
= inputBuffer
->StartingS
;
2387 cdb
->PLAY_AUDIO_MSF
.StartingF
= inputBuffer
->StartingF
;
2389 cdb
->PLAY_AUDIO_MSF
.EndingM
= inputBuffer
->EndingM
;
2390 cdb
->PLAY_AUDIO_MSF
.EndingS
= inputBuffer
->EndingS
;
2391 cdb
->PLAY_AUDIO_MSF
.EndingF
= inputBuffer
->EndingF
;
2393 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2394 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2395 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_NO_DATA_TRANSFER
);
2397 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2402 case IOCTL_CDROM_READ_Q_CHANNEL
: {
2404 PCDROM_SUB_Q_DATA_FORMAT inputBuffer
=
2405 Irp
->AssociatedIrp
.SystemBuffer
;
2408 // Allocate buffer for subq channel information.
2411 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
2412 sizeof(SUB_Q_CHANNEL_DATA
));
2415 Irp
->IoStatus
.Information
= 0;
2416 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2417 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2418 ExFreePool(senseBuffer
);
2421 IoStartNextPacket(DeviceObject
, FALSE
);
2426 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2432 if (!irp2
->MdlAddress
) {
2433 Irp
->IoStatus
.Information
= 0;
2434 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2435 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2436 ExFreePool(senseBuffer
);
2438 ExFreePool(dataBuffer
);
2440 IoStartNextPacket(DeviceObject
, FALSE
);
2448 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2450 srb
->DataBuffer
= dataBuffer
;
2453 // Always logical unit 0, but only use MSF addressing
2454 // for IOCTL_CDROM_CURRENT_POSITION
2457 if (inputBuffer
->Format
==IOCTL_CDROM_CURRENT_POSITION
)
2458 cdb
->SUBCHANNEL
.Msf
= CDB_USE_MSF
;
2461 // Return subchannel data
2464 cdb
->SUBCHANNEL
.SubQ
= CDB_SUBCHANNEL_BLOCK
;
2467 // Specify format of informatin to return
2470 cdb
->SUBCHANNEL
.Format
= inputBuffer
->Format
;
2473 // Specify which track to access (only used by Track ISRC reads)
2476 if (inputBuffer
->Format
==IOCTL_CDROM_TRACK_ISRC
) {
2477 cdb
->SUBCHANNEL
.TrackNumber
= inputBuffer
->Track
;
2481 // Set size of channel data -- however, this is dependent on
2482 // what information we are requesting (which Format)
2485 switch( inputBuffer
->Format
) {
2487 case IOCTL_CDROM_CURRENT_POSITION
:
2488 transferByteCount
= sizeof(SUB_Q_CURRENT_POSITION
);
2491 case IOCTL_CDROM_MEDIA_CATALOG
:
2492 transferByteCount
= sizeof(SUB_Q_MEDIA_CATALOG_NUMBER
);
2495 case IOCTL_CDROM_TRACK_ISRC
:
2496 transferByteCount
= sizeof(SUB_Q_TRACK_ISRC
);
2500 cdb
->SUBCHANNEL
.AllocationLength
[0] = (UCHAR
) (transferByteCount
>> 8);
2501 cdb
->SUBCHANNEL
.AllocationLength
[1] = (UCHAR
) (transferByteCount
& 0xFF);
2502 cdb
->SUBCHANNEL
.OperationCode
= SCSIOP_READ_SUB_CHANNEL
;
2503 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2504 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
2505 srb
->DataTransferLength
= transferByteCount
;
2506 srb
->CdbLength
= 10;
2507 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2509 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2514 case IOCTL_CDROM_PAUSE_AUDIO
: {
2516 cdb
->PAUSE_RESUME
.OperationCode
= SCSIOP_PAUSE_RESUME
;
2517 cdb
->PAUSE_RESUME
.Action
= CDB_AUDIO_PAUSE
;
2519 srb
->CdbLength
= 10;
2520 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2521 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2522 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_NO_DATA_TRANSFER
);
2524 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2528 case IOCTL_CDROM_RESUME_AUDIO
: {
2530 cdb
->PAUSE_RESUME
.OperationCode
= SCSIOP_PAUSE_RESUME
;
2531 cdb
->PAUSE_RESUME
.Action
= CDB_AUDIO_RESUME
;
2533 srb
->CdbLength
= 10;
2534 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2535 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2536 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_NO_DATA_TRANSFER
);
2538 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2542 case IOCTL_CDROM_SEEK_AUDIO_MSF
: {
2544 PCDROM_SEEK_AUDIO_MSF inputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
2545 ULONG logicalBlockAddress
;
2547 logicalBlockAddress
= MSF_TO_LBA(inputBuffer
->M
, inputBuffer
->S
, inputBuffer
->F
);
2549 cdb
->SEEK
.OperationCode
= SCSIOP_SEEK
;
2550 cdb
->SEEK
.LogicalBlockAddress
[0] = ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte3
;
2551 cdb
->SEEK
.LogicalBlockAddress
[1] = ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte2
;
2552 cdb
->SEEK
.LogicalBlockAddress
[2] = ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte1
;
2553 cdb
->SEEK
.LogicalBlockAddress
[3] = ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte0
;
2555 srb
->CdbLength
= 10;
2556 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2557 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2558 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_NO_DATA_TRANSFER
);
2560 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2565 case IOCTL_CDROM_STOP_AUDIO
: {
2567 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
2568 cdb
->START_STOP
.Immediate
= 1;
2569 cdb
->START_STOP
.Start
= 0;
2570 cdb
->START_STOP
.LoadEject
= 0;
2573 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2575 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2576 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_NO_DATA_TRANSFER
);
2578 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2582 case IOCTL_CDROM_GET_CONTROL
: {
2584 // Allocate buffer for volume control information.
2587 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
2591 Irp
->IoStatus
.Information
= 0;
2592 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2593 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2594 ExFreePool(senseBuffer
);
2597 IoStartNextPacket(DeviceObject
, FALSE
);
2602 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2608 if (!irp2
->MdlAddress
) {
2609 Irp
->IoStatus
.Information
= 0;
2610 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2611 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2612 ExFreePool(senseBuffer
);
2614 ExFreePool(dataBuffer
);
2616 IoStartNextPacket(DeviceObject
, FALSE
);
2624 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2625 srb
->DataBuffer
= dataBuffer
;
2627 RtlZeroMemory(dataBuffer
, MODE_DATA_SIZE
);
2630 // Setup for either 6 or 10 byte CDBs.
2635 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
2636 cdb
->MODE_SENSE
.PageCode
= CDROM_AUDIO_CONTROL_PAGE
;
2637 cdb
->MODE_SENSE
.AllocationLength
= MODE_DATA_SIZE
;
2640 // Disable block descriptors.
2643 cdb
->MODE_SENSE
.Dbd
= TRUE
;
2648 cdb
->MODE_SENSE10
.OperationCode
= SCSIOP_MODE_SENSE10
;
2649 cdb
->MODE_SENSE10
.PageCode
= CDROM_AUDIO_CONTROL_PAGE
;
2650 cdb
->MODE_SENSE10
.AllocationLength
[0] = (UCHAR
)(MODE_DATA_SIZE
>> 8);
2651 cdb
->MODE_SENSE10
.AllocationLength
[1] = (UCHAR
)(MODE_DATA_SIZE
& 0xFF);
2654 // Disable block descriptors.
2657 cdb
->MODE_SENSE10
.Dbd
= TRUE
;
2659 srb
->CdbLength
= 10;
2662 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2663 srb
->DataTransferLength
= MODE_DATA_SIZE
;
2664 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2665 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
2667 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2672 case IOCTL_CDROM_GET_VOLUME
:
2673 case IOCTL_CDROM_SET_VOLUME
: {
2675 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
2679 Irp
->IoStatus
.Information
= 0;
2680 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2681 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2682 ExFreePool(senseBuffer
);
2685 IoStartNextPacket(DeviceObject
, FALSE
);
2689 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2695 if (!irp2
->MdlAddress
) {
2696 Irp
->IoStatus
.Information
= 0;
2697 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2698 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2699 ExFreePool(senseBuffer
);
2701 ExFreePool(dataBuffer
);
2703 IoStartNextPacket(DeviceObject
, FALSE
);
2711 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2712 srb
->DataBuffer
= dataBuffer
;
2714 RtlZeroMemory(dataBuffer
, MODE_DATA_SIZE
);
2718 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
2719 cdb
->MODE_SENSE
.PageCode
= CDROM_AUDIO_CONTROL_PAGE
;
2720 cdb
->MODE_SENSE
.AllocationLength
= MODE_DATA_SIZE
;
2726 cdb
->MODE_SENSE10
.OperationCode
= SCSIOP_MODE_SENSE10
;
2727 cdb
->MODE_SENSE10
.PageCode
= CDROM_AUDIO_CONTROL_PAGE
;
2728 cdb
->MODE_SENSE10
.AllocationLength
[0] = (UCHAR
)(MODE_DATA_SIZE
>> 8);
2729 cdb
->MODE_SENSE10
.AllocationLength
[1] = (UCHAR
)(MODE_DATA_SIZE
& 0xFF);
2731 srb
->CdbLength
= 10;
2734 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2735 srb
->DataTransferLength
= MODE_DATA_SIZE
;
2736 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2737 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
2739 if (currentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_SET_VOLUME
) {
2742 // Setup a different completion routine as the mode sense data is needed in order
2743 // to send the mode select.
2746 IoSetCompletionRoutine(irp2
,
2747 CdRomSetVolumeIntermediateCompletion
,
2755 IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2763 // Just complete the request - CdRomClassIoctlCompletion will take
2764 // care of it for us
2767 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2774 // If a read or an unhandled IRP_MJ_XX, end up here. The unhandled IRP_MJ's
2775 // are expected and composed of AutoRun Irps, at present.
2778 IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
2785 ScsiCdRomReadVerification(
2786 IN PDEVICE_OBJECT DeviceObject
,
2792 Routine Description:
2794 This is the entry called by the I/O system for read requests.
2795 It builds the SRB and sends it to the port driver.
2799 DeviceObject - the system object for the device.
2809 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2810 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
2811 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
2812 LARGE_INTEGER startingOffset
= currentIrpStack
->Parameters
.Read
.ByteOffset
;
2815 // If the cd is playing music then reject this request.
2818 if (PLAY_ACTIVE(deviceExtension
)) {
2819 Irp
->IoStatus
.Status
= STATUS_DEVICE_BUSY
;
2820 return STATUS_DEVICE_BUSY
;
2824 // Verify parameters of this request.
2825 // Check that ending sector is on disc and
2826 // that number of bytes to transfer is a multiple of
2830 startingOffset
.QuadPart
= currentIrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+
2833 if (!deviceExtension
->DiskGeometry
->BytesPerSector
) {
2834 deviceExtension
->DiskGeometry
->BytesPerSector
= 2048;
2837 if ((startingOffset
.QuadPart
> deviceExtension
->PartitionLength
.QuadPart
) ||
2838 (transferByteCount
& deviceExtension
->DiskGeometry
->BytesPerSector
- 1)) {
2840 DebugPrint((1,"ScsiCdRomRead: Invalid I/O parameters\n"));
2841 DebugPrint((1, "\toffset %x:%x, Length %x:%x\n",
2842 startingOffset
.u
.HighPart
,
2843 startingOffset
.u
.LowPart
,
2844 deviceExtension
->PartitionLength
.u
.HighPart
,
2845 deviceExtension
->PartitionLength
.u
.LowPart
));
2846 DebugPrint((1, "\tbps %x\n", deviceExtension
->DiskGeometry
->BytesPerSector
));
2849 // Fail request with status of invalid parameters.
2852 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
2854 return STATUS_INVALID_PARAMETER
;
2858 return STATUS_SUCCESS
;
2860 } // end ScsiCdRomReadVerification()
2865 CdRomDeviceControlCompletion(
2866 IN PDEVICE_OBJECT DeviceObject
,
2871 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2872 PDEVICE_EXTENSION physicalExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
2873 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
2874 PCDROM_DATA cdData
= (PCDROM_DATA
)(deviceExtension
+ 1);
2875 BOOLEAN use6Byte
= cdData
->XAFlags
& XA_USE_6_BYTE
;
2876 PIO_STACK_LOCATION realIrpStack
;
2877 PIO_STACK_LOCATION realIrpNextStack
;
2878 PSCSI_REQUEST_BLOCK srb
= Context
;
2879 PIRP realIrp
= NULL
;
2884 // Extract the 'real' irp from the irpstack.
2887 realIrp
= (PIRP
) irpStack
->Parameters
.Others
.Argument2
;
2888 realIrpStack
= IoGetCurrentIrpStackLocation(realIrp
);
2889 realIrpNextStack
= IoGetNextIrpStackLocation(realIrp
);
2892 // Check SRB status for success of completing request.
2895 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
2898 "CdRomDeviceControlCompletion: Irp %lx, Srb %lx Real Irp %lx Status %lx\n",
2905 // Release the queue if it is frozen.
2908 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
2909 DebugPrint((2, "CdRomDeviceControlCompletion: Releasing Queue\n"));
2910 ScsiClassReleaseQueue(DeviceObject
);
2914 retry
= ScsiClassInterpretSenseInfo(DeviceObject
,
2916 irpStack
->MajorFunction
,
2917 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
,
2918 MAXIMUM_RETRIES
- ((ULONG
)realIrpNextStack
->Parameters
.Others
.Argument1
),
2921 DebugPrint((2, "CdRomDeviceControlCompletion: IRP will %sbe retried\n",
2922 (retry
? "" : "not ")));
2925 // Some of the Device Controls need special cases on non-Success status's.
2928 if (realIrpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
) {
2929 if ((realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_GET_LAST_SESSION
) ||
2930 (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_READ_TOC
) ||
2931 (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_GET_CONTROL
) ||
2932 (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_GET_VOLUME
)) {
2934 if (status
== STATUS_DATA_OVERRUN
) {
2935 status
= STATUS_SUCCESS
;
2940 if (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_READ_Q_CHANNEL
) {
2941 PLAY_ACTIVE(deviceExtension
) = FALSE
;
2946 // If the status is verified required and the this request
2947 // should bypass verify required then retry the request.
2950 if (realIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
2951 status
== STATUS_VERIFY_REQUIRED
) {
2953 if (((realIrpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
) ||
2954 (realIrpStack
->MajorFunction
== IRP_MJ_INTERNAL_DEVICE_CONTROL
)) &&
2955 (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_CHECK_VERIFY
)) {
2958 // Update the geometry information, as the media could have changed.
2959 // The completion routine for this will complete the real irp and start
2963 status
= CdRomUpdateCapacity(deviceExtension
,realIrp
, NULL
);
2964 DebugPrint((2, "CdRomDeviceControlCompletion: [%lx] CdRomUpdateCapacity completed with status %lx\n", realIrp
, status
));
2965 ASSERT(status
== STATUS_PENDING
);
2967 return STATUS_MORE_PROCESSING_REQUIRED
;
2971 status
= STATUS_IO_DEVICE_ERROR
;
2977 if (retry
&& (realIrpNextStack
->Parameters
.Others
.Argument1
= (ULONG
)realIrpNextStack
->Parameters
.Others
.Argument1
-1)) {
2980 if (((ULONG
)realIrpNextStack
->Parameters
.Others
.Argument1
)) {
2986 DebugPrint((1, "Retry request %lx - Calling StartIo\n", Irp
));
2989 ExFreePool(srb
->SenseInfoBuffer
);
2990 if (srb
->DataBuffer
) {
2991 ExFreePool(srb
->DataBuffer
);
2994 if (Irp
->MdlAddress
) {
2995 IoFreeMdl(Irp
->MdlAddress
);
3001 // Call StartIo directly since IoStartNextPacket hasn't been called,
3002 // the serialisation is still intact.
3005 ScsiCdRomStartIo(DeviceObject
, realIrp
);
3006 return STATUS_MORE_PROCESSING_REQUIRED
;
3011 // Exhausted retries. Fall through and complete the request with the appropriate status.
3018 // Set status for successful request.
3021 status
= STATUS_SUCCESS
;
3024 if (NT_SUCCESS(status
)) {
3026 switch (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
) {
3028 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
: {
3030 PREAD_CAPACITY_DATA readCapacityBuffer
= srb
->DataBuffer
;
3037 // Swizzle bytes from Read Capacity and translate into
3038 // the necessary geometry information in the device extension.
3041 tmp
= readCapacityBuffer
->BytesPerBlock
;
3042 ((PFOUR_BYTE
)&bps
)->Byte0
= ((PFOUR_BYTE
)&tmp
)->Byte3
;
3043 ((PFOUR_BYTE
)&bps
)->Byte1
= ((PFOUR_BYTE
)&tmp
)->Byte2
;
3044 ((PFOUR_BYTE
)&bps
)->Byte2
= ((PFOUR_BYTE
)&tmp
)->Byte1
;
3045 ((PFOUR_BYTE
)&bps
)->Byte3
= ((PFOUR_BYTE
)&tmp
)->Byte0
;
3048 // Insure that bps is a power of 2.
3049 // This corrects a problem with the HP 4020i CDR where it
3050 // returns an incorrect number for bytes per sector.
3056 lastBit
= (ULONG
) -1;
3064 deviceExtension
->DiskGeometry
->BytesPerSector
= bps
;
3067 "CdRomDeviceControlCompletion: Calculated bps %#x\n",
3068 deviceExtension
->DiskGeometry
->BytesPerSector
));
3071 // Copy last sector in reverse byte order.
3074 tmp
= readCapacityBuffer
->LogicalBlockAddress
;
3075 ((PFOUR_BYTE
)&lastSector
)->Byte0
= ((PFOUR_BYTE
)&tmp
)->Byte3
;
3076 ((PFOUR_BYTE
)&lastSector
)->Byte1
= ((PFOUR_BYTE
)&tmp
)->Byte2
;
3077 ((PFOUR_BYTE
)&lastSector
)->Byte2
= ((PFOUR_BYTE
)&tmp
)->Byte1
;
3078 ((PFOUR_BYTE
)&lastSector
)->Byte3
= ((PFOUR_BYTE
)&tmp
)->Byte0
;
3081 // Calculate sector to byte shift.
3084 WHICH_BIT(bps
, deviceExtension
->SectorShift
);
3086 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Sector size is %d\n",
3087 deviceExtension
->DiskGeometry
->BytesPerSector
));
3089 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Number of Sectors is %d\n",
3093 // Calculate media capacity in bytes.
3096 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(lastSector
+ 1);
3099 // Calculate number of cylinders.
3102 deviceExtension
->DiskGeometry
->Cylinders
.QuadPart
= (LONGLONG
)((lastSector
+ 1)/(32 * 64));
3104 deviceExtension
->PartitionLength
.QuadPart
=
3105 (deviceExtension
->PartitionLength
.QuadPart
<< deviceExtension
->SectorShift
);
3107 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
3110 // This device supports removable media.
3113 deviceExtension
->DiskGeometry
->MediaType
= RemovableMedia
;
3118 // Assume media type is fixed disk.
3121 deviceExtension
->DiskGeometry
->MediaType
= FixedMedia
;
3125 // Assume sectors per track are 32;
3128 deviceExtension
->DiskGeometry
->SectorsPerTrack
= 32;
3131 // Assume tracks per cylinder (number of heads) is 64.
3134 deviceExtension
->DiskGeometry
->TracksPerCylinder
= 64;
3137 // Copy the device extension's geometry info into the user buffer.
3140 RtlMoveMemory(realIrp
->AssociatedIrp
.SystemBuffer
,
3141 deviceExtension
->DiskGeometry
,
3142 sizeof(DISK_GEOMETRY
));
3145 // update information field.
3148 realIrp
->IoStatus
.Information
= sizeof(DISK_GEOMETRY
);
3152 case IOCTL_CDROM_CHECK_VERIFY
:
3154 if((realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_CHECK_VERIFY
) &&
3155 (realIrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
)) {
3157 *((PULONG
)realIrp
->AssociatedIrp
.SystemBuffer
) =
3158 physicalExtension
->MediaChangeCount
;
3159 realIrp
->IoStatus
.Information
= sizeof(ULONG
);
3161 realIrp
->IoStatus
.Information
= 0;
3164 DebugPrint((2, "CdRomDeviceControlCompletion: [%lx] completing CHECK_VERIFY buddy irp %lx\n", realIrp
, Irp
));
3167 case IOCTL_CDROM_GET_LAST_SESSION
:
3168 case IOCTL_CDROM_READ_TOC
: {
3170 PCDROM_TOC toc
= srb
->DataBuffer
;
3173 // Copy the device extension's geometry info into the user buffer.
3176 RtlMoveMemory(realIrp
->AssociatedIrp
.SystemBuffer
,
3178 srb
->DataTransferLength
);
3181 // update information field.
3184 realIrp
->IoStatus
.Information
= srb
->DataTransferLength
;
3188 case IOCTL_CDROM_PLAY_AUDIO_MSF
:
3190 PLAY_ACTIVE(deviceExtension
) = TRUE
;
3194 case IOCTL_CDROM_READ_Q_CHANNEL
: {
3196 PSUB_Q_CHANNEL_DATA userChannelData
= realIrp
->AssociatedIrp
.SystemBuffer
;
3197 PCDROM_SUB_Q_DATA_FORMAT inputBuffer
= realIrp
->AssociatedIrp
.SystemBuffer
;
3198 PSUB_Q_CHANNEL_DATA subQPtr
= srb
->DataBuffer
;
3201 switch( inputBuffer
->Format
) {
3203 case IOCTL_CDROM_CURRENT_POSITION
:
3204 DebugPrint((2,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr
->CurrentPosition
.Header
.AudioStatus
));
3205 DebugPrint((2,"CdRomDeviceControlCompletion: ADR = 0x%x\n", subQPtr
->CurrentPosition
.ADR
));
3206 DebugPrint((2,"CdRomDeviceControlCompletion: Control = 0x%x\n", subQPtr
->CurrentPosition
.Control
));
3207 DebugPrint((2,"CdRomDeviceControlCompletion: Track = %u\n", subQPtr
->CurrentPosition
.TrackNumber
));
3208 DebugPrint((2,"CdRomDeviceControlCompletion: Index = %u\n", subQPtr
->CurrentPosition
.IndexNumber
));
3209 DebugPrint((2,"CdRomDeviceControlCompletion: Absolute Address = %x\n", *((PULONG
)subQPtr
->CurrentPosition
.AbsoluteAddress
) ));
3210 DebugPrint((2,"CdRomDeviceControlCompletion: Relative Address = %x\n", *((PULONG
)subQPtr
->CurrentPosition
.TrackRelativeAddress
) ));
3213 case IOCTL_CDROM_MEDIA_CATALOG
:
3214 DebugPrint((2,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr
->MediaCatalog
.Header
.AudioStatus
));
3215 DebugPrint((2,"CdRomDeviceControlCompletion: Mcval is %u\n", subQPtr
->MediaCatalog
.Mcval
));
3218 case IOCTL_CDROM_TRACK_ISRC
:
3219 DebugPrint((2,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr
->TrackIsrc
.Header
.AudioStatus
));
3220 DebugPrint((2,"CdRomDeviceControlCompletion: Tcval is %u\n", subQPtr
->TrackIsrc
.Tcval
));
3227 // Update the play active status.
3230 if (subQPtr
->CurrentPosition
.Header
.AudioStatus
== AUDIO_STATUS_IN_PROGRESS
) {
3232 PLAY_ACTIVE(deviceExtension
) = TRUE
;
3236 PLAY_ACTIVE(deviceExtension
) = FALSE
;
3241 // Check if output buffer is large enough to contain
3245 if (realIrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
3246 srb
->DataTransferLength
) {
3248 srb
->DataTransferLength
=
3249 realIrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
3253 // Copy our buffer into users.
3256 RtlMoveMemory(userChannelData
,
3258 srb
->DataTransferLength
);
3260 realIrp
->IoStatus
.Information
= srb
->DataTransferLength
;
3264 case IOCTL_CDROM_PAUSE_AUDIO
:
3266 PLAY_ACTIVE(deviceExtension
) = FALSE
;
3267 realIrp
->IoStatus
.Information
= 0;
3270 case IOCTL_CDROM_RESUME_AUDIO
:
3272 realIrp
->IoStatus
.Information
= 0;
3275 case IOCTL_CDROM_SEEK_AUDIO_MSF
:
3277 realIrp
->IoStatus
.Information
= 0;
3280 case IOCTL_CDROM_STOP_AUDIO
:
3282 PLAY_ACTIVE(deviceExtension
) = FALSE
;
3284 realIrp
->IoStatus
.Information
= 0;
3287 case IOCTL_CDROM_GET_CONTROL
: {
3289 PCDROM_AUDIO_CONTROL audioControl
= srb
->DataBuffer
;
3290 PAUDIO_OUTPUT audioOutput
;
3291 ULONG bytesTransferred
;
3293 audioOutput
= ScsiClassFindModePage((PCHAR
)audioControl
,
3294 srb
->DataTransferLength
,
3295 CDROM_AUDIO_CONTROL_PAGE
,
3298 // Verify the page is as big as expected.
3301 bytesTransferred
= (PCHAR
) audioOutput
- (PCHAR
) audioControl
+
3302 sizeof(AUDIO_OUTPUT
);
3304 if (audioOutput
!= NULL
&&
3305 srb
->DataTransferLength
>= bytesTransferred
) {
3307 audioControl
->LbaFormat
= audioOutput
->LbaFormat
;
3309 audioControl
->LogicalBlocksPerSecond
=
3310 (audioOutput
->LogicalBlocksPerSecond
[0] << (UCHAR
)8) |
3311 audioOutput
->LogicalBlocksPerSecond
[1];
3313 realIrp
->IoStatus
.Information
= sizeof(CDROM_AUDIO_CONTROL
);
3316 realIrp
->IoStatus
.Information
= 0;
3317 status
= STATUS_INVALID_DEVICE_REQUEST
;
3322 case IOCTL_CDROM_GET_VOLUME
: {
3324 PAUDIO_OUTPUT audioOutput
;
3325 PVOLUME_CONTROL volumeControl
= srb
->DataBuffer
;
3326 ULONG i
,bytesTransferred
;
3328 audioOutput
= ScsiClassFindModePage((PCHAR
)volumeControl
,
3329 srb
->DataTransferLength
,
3330 CDROM_AUDIO_CONTROL_PAGE
,
3334 // Verify the page is as big as expected.
3337 bytesTransferred
= (PCHAR
) audioOutput
- (PCHAR
) volumeControl
+
3338 sizeof(AUDIO_OUTPUT
);
3340 if (audioOutput
!= NULL
&&
3341 srb
->DataTransferLength
>= bytesTransferred
) {
3343 for (i
=0; i
<4; i
++) {
3344 volumeControl
->PortVolume
[i
] =
3345 audioOutput
->PortOutput
[i
].Volume
;
3349 // Set bytes transferred in IRP.
3352 realIrp
->IoStatus
.Information
= sizeof(VOLUME_CONTROL
);
3355 realIrp
->IoStatus
.Information
= 0;
3356 status
= STATUS_INVALID_DEVICE_REQUEST
;
3362 case IOCTL_CDROM_SET_VOLUME
:
3364 realIrp
->IoStatus
.Information
= sizeof(VOLUME_CONTROL
);
3370 realIrp
->IoStatus
.Information
= 0;
3371 status
= STATUS_INVALID_DEVICE_REQUEST
;
3377 // Deallocate srb and sense buffer.
3381 if (srb
->DataBuffer
) {
3382 ExFreePool(srb
->DataBuffer
);
3384 if (srb
->SenseInfoBuffer
) {
3385 ExFreePool(srb
->SenseInfoBuffer
);
3390 if (realIrp
->PendingReturned
) {
3391 IoMarkIrpPending(realIrp
);
3394 if (Irp
->MdlAddress
) {
3395 IoFreeMdl(Irp
->MdlAddress
);
3401 // Set status in completing IRP.
3404 realIrp
->IoStatus
.Status
= status
;
3407 // Set the hard error if necessary.
3410 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
3413 // Store DeviceObject for filesystem, and clear
3414 // in IoStatus.Information field.
3417 DebugPrint((1, "CdRomDeviceCompletion - Setting Hard Error on realIrp %lx\n",
3419 IoSetHardErrorOrVerifyDevice(realIrp
, DeviceObject
);
3420 realIrp
->IoStatus
.Information
= 0;
3423 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
3425 IoStartNextPacket(DeviceObject
, FALSE
);
3427 return STATUS_MORE_PROCESSING_REQUIRED
;
3432 CdRomSetVolumeIntermediateCompletion(
3433 IN PDEVICE_OBJECT DeviceObject
,
3438 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3439 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3440 PCDROM_DATA cdData
= (PCDROM_DATA
)(deviceExtension
+ 1);
3441 BOOLEAN use6Byte
= cdData
->XAFlags
& XA_USE_6_BYTE
;
3442 PIO_STACK_LOCATION realIrpStack
;
3443 PIO_STACK_LOCATION realIrpNextStack
;
3444 PSCSI_REQUEST_BLOCK srb
= Context
;
3445 PIRP realIrp
= NULL
;
3450 // Extract the 'real' irp from the irpstack.
3453 realIrp
= (PIRP
) irpStack
->Parameters
.Others
.Argument2
;
3454 realIrpStack
= IoGetCurrentIrpStackLocation(realIrp
);
3455 realIrpNextStack
= IoGetNextIrpStackLocation(realIrp
);
3458 // Check SRB status for success of completing request.
3461 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
3464 "CdRomSetVolumeIntermediateCompletion: Irp %lx, Srb %lx Real Irp\n",
3470 // Release the queue if it is frozen.
3473 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
3474 ScsiClassReleaseQueue(DeviceObject
);
3478 retry
= ScsiClassInterpretSenseInfo(DeviceObject
,
3480 irpStack
->MajorFunction
,
3481 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
,
3482 MAXIMUM_RETRIES
- ((ULONG
)realIrpNextStack
->Parameters
.Others
.Argument1
),
3485 if (status
== STATUS_DATA_OVERRUN
) {
3486 status
= STATUS_SUCCESS
;
3491 // If the status is verified required and the this request
3492 // should bypass verify required then retry the request.
3495 if (realIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
3496 status
== STATUS_VERIFY_REQUIRED
) {
3498 status
= STATUS_IO_DEVICE_ERROR
;
3502 if (retry
&& (realIrpNextStack
->Parameters
.Others
.Argument1
= (ULONG
)realIrpNextStack
->Parameters
.Others
.Argument1
-1)) {
3504 if (((ULONG
)realIrpNextStack
->Parameters
.Others
.Argument1
)) {
3510 DebugPrint((1, "Retry request %lx - Calling StartIo\n", Irp
));
3513 ExFreePool(srb
->SenseInfoBuffer
);
3514 ExFreePool(srb
->DataBuffer
);
3516 if (Irp
->MdlAddress
) {
3517 IoFreeMdl(Irp
->MdlAddress
);
3523 // Call StartIo directly since IoStartNextPacket hasn't been called,
3524 // the serialisation is still intact.
3526 ScsiCdRomStartIo(DeviceObject
, realIrp
);
3527 return STATUS_MORE_PROCESSING_REQUIRED
;
3532 // Exhausted retries. Fall through and complete the request with the appropriate status.
3539 // Set status for successful request.
3542 status
= STATUS_SUCCESS
;
3545 if (NT_SUCCESS(status
)) {
3547 PAUDIO_OUTPUT audioInput
= NULL
;
3548 PAUDIO_OUTPUT audioOutput
;
3549 PVOLUME_CONTROL volumeControl
= realIrp
->AssociatedIrp
.SystemBuffer
;
3550 ULONG i
,bytesTransferred
,headerLength
;
3554 audioInput
= ScsiClassFindModePage((PCHAR
)srb
->DataBuffer
,
3555 srb
->DataTransferLength
,
3556 CDROM_AUDIO_CONTROL_PAGE
,
3560 // Check to make sure the mode sense data is valid before we go on
3563 if(audioInput
== NULL
) {
3565 DebugPrint((1, "Mode Sense Page %d not found\n",
3566 CDROM_AUDIO_CONTROL_PAGE
));
3568 realIrp
->IoStatus
.Information
= 0;
3569 realIrp
->IoStatus
.Status
= STATUS_IO_DEVICE_ERROR
;
3570 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
3571 ExFreePool(srb
->SenseInfoBuffer
);
3573 IoFreeMdl(Irp
->MdlAddress
);
3575 return STATUS_MORE_PROCESSING_REQUIRED
;
3579 headerLength
= sizeof(MODE_PARAMETER_HEADER
);
3581 headerLength
= sizeof(MODE_PARAMETER_HEADER10
);
3584 bytesTransferred
= sizeof(AUDIO_OUTPUT
) + headerLength
;
3587 // Allocate a new buffer for the mode select.
3590 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, bytesTransferred
);
3593 realIrp
->IoStatus
.Information
= 0;
3594 realIrp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3595 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
3596 ExFreePool(srb
->SenseInfoBuffer
);
3598 IoFreeMdl(Irp
->MdlAddress
);
3600 return STATUS_MORE_PROCESSING_REQUIRED
;
3603 RtlZeroMemory(dataBuffer
, bytesTransferred
);
3606 // Rebuild the data buffer to include the user requested values.
3609 audioOutput
= (PAUDIO_OUTPUT
) ((PCHAR
) dataBuffer
+ headerLength
);
3611 for (i
=0; i
<4; i
++) {
3612 audioOutput
->PortOutput
[i
].Volume
=
3613 volumeControl
->PortVolume
[i
];
3614 audioOutput
->PortOutput
[i
].ChannelSelection
=
3615 audioInput
->PortOutput
[i
].ChannelSelection
;
3618 audioOutput
->CodePage
= CDROM_AUDIO_CONTROL_PAGE
;
3619 audioOutput
->ParameterLength
= sizeof(AUDIO_OUTPUT
) - 2;
3620 audioOutput
->Immediate
= MODE_SELECT_IMMEDIATE
;
3623 // Free the old data buffer, mdl.
3626 ExFreePool(srb
->DataBuffer
);
3627 IoFreeMdl(Irp
->MdlAddress
);
3633 cdb
= (PCDB
)srb
->Cdb
;
3634 RtlZeroMemory(cdb
, CDB12GENERIC_LENGTH
);
3636 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
3637 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
3638 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_OUT
);
3639 srb
->DataTransferLength
= bytesTransferred
;
3643 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
3644 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
) bytesTransferred
;
3645 cdb
->MODE_SELECT
.PFBit
= 1;
3649 cdb
->MODE_SELECT10
.OperationCode
= SCSIOP_MODE_SELECT10
;
3650 cdb
->MODE_SELECT10
.ParameterListLength
[0] = (UCHAR
) (bytesTransferred
>> 8);
3651 cdb
->MODE_SELECT10
.ParameterListLength
[1] = (UCHAR
) (bytesTransferred
& 0xFF);
3652 cdb
->MODE_SELECT10
.PFBit
= 1;
3653 srb
->CdbLength
= 10;
3660 Irp
->MdlAddress
= IoAllocateMdl(dataBuffer
,
3666 if (!Irp
->MdlAddress
) {
3667 realIrp
->IoStatus
.Information
= 0;
3668 realIrp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3669 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
3670 ExFreePool(srb
->SenseInfoBuffer
);
3672 ExFreePool(dataBuffer
);
3674 return STATUS_MORE_PROCESSING_REQUIRED
;
3678 MmBuildMdlForNonPagedPool(Irp
->MdlAddress
);
3679 srb
->DataBuffer
= dataBuffer
;
3681 irpStack
= IoGetNextIrpStackLocation(Irp
);
3682 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
3683 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
3684 irpStack
->Parameters
.Scsi
.Srb
= srb
;
3687 // reset the irp completion.
3690 IoSetCompletionRoutine(Irp
,
3691 CdRomDeviceControlCompletion
,
3697 // Call the port driver.
3700 IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
3702 return STATUS_MORE_PROCESSING_REQUIRED
;
3706 // Deallocate srb and sense buffer.
3710 if (srb
->DataBuffer
) {
3711 ExFreePool(srb
->DataBuffer
);
3713 if (srb
->SenseInfoBuffer
) {
3714 ExFreePool(srb
->SenseInfoBuffer
);
3719 if (Irp
->PendingReturned
) {
3720 IoMarkIrpPending(Irp
);
3723 if (realIrp
->PendingReturned
) {
3724 IoMarkIrpPending(realIrp
);
3727 if (Irp
->MdlAddress
) {
3728 IoFreeMdl(Irp
->MdlAddress
);
3734 // Set status in completing IRP.
3737 realIrp
->IoStatus
.Status
= status
;
3740 // Set the hard error if necessary.
3743 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
3746 // Store DeviceObject for filesystem, and clear
3747 // in IoStatus.Information field.
3750 IoSetHardErrorOrVerifyDevice(realIrp
, DeviceObject
);
3751 realIrp
->IoStatus
.Information
= 0;
3754 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
3756 IoStartNextPacket(DeviceObject
, FALSE
);
3758 return STATUS_MORE_PROCESSING_REQUIRED
;
3764 CdRomSwitchModeCompletion(
3765 IN PDEVICE_OBJECT DeviceObject
,
3770 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3771 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3772 PCDROM_DATA cdData
= (PCDROM_DATA
)(deviceExtension
+ 1);
3773 PIO_STACK_LOCATION realIrpStack
;
3774 PIO_STACK_LOCATION realIrpNextStack
;
3775 PSCSI_REQUEST_BLOCK srb
= Context
;
3776 PIRP realIrp
= NULL
;
3781 // Extract the 'real' irp from the irpstack.
3784 realIrp
= (PIRP
) irpStack
->Parameters
.Others
.Argument2
;
3785 realIrpStack
= IoGetCurrentIrpStackLocation(realIrp
);
3786 realIrpNextStack
= IoGetNextIrpStackLocation(realIrp
);
3789 // Check SRB status for success of completing request.
3792 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
3795 "CdRomSetVolumeIntermediateCompletion: Irp %lx, Srb %lx Real Irp\n",
3801 // Release the queue if it is frozen.
3804 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
3805 ScsiClassReleaseQueue(DeviceObject
);
3809 retry
= ScsiClassInterpretSenseInfo(DeviceObject
,
3811 irpStack
->MajorFunction
,
3812 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
,
3813 MAXIMUM_RETRIES
- ((ULONG
)realIrpNextStack
->Parameters
.Others
.Argument1
),
3817 // If the status is verified required and the this request
3818 // should bypass verify required then retry the request.
3821 if (realIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
3822 status
== STATUS_VERIFY_REQUIRED
) {
3824 status
= STATUS_IO_DEVICE_ERROR
;
3828 if (retry
&& (realIrpNextStack
->Parameters
.Others
.Argument1
= (ULONG
)realIrpNextStack
->Parameters
.Others
.Argument1
-1)) {
3830 if (((ULONG
)realIrpNextStack
->Parameters
.Others
.Argument1
)) {
3836 DebugPrint((1, "Retry request %lx - Calling StartIo\n", Irp
));
3839 ExFreePool(srb
->SenseInfoBuffer
);
3840 ExFreePool(srb
->DataBuffer
);
3842 if (Irp
->MdlAddress
) {
3843 IoFreeMdl(Irp
->MdlAddress
);
3849 // Call StartIo directly since IoStartNextPacket hasn't been called,
3850 // the serialisation is still intact.
3853 ScsiCdRomStartIo(DeviceObject
, realIrp
);
3854 return STATUS_MORE_PROCESSING_REQUIRED
;
3859 // Exhausted retries. Fall through and complete the request with the appropriate status.
3865 // Set status for successful request.
3868 status
= STATUS_SUCCESS
;
3871 if (NT_SUCCESS(status
)) {
3873 ULONG sectorSize
, startingSector
, transferByteCount
;
3877 // Update device ext. to show which mode we are currently using.
3880 sectorSize
= cdData
->u1
.BlockDescriptor
.BlockLength
[0] << 16;
3881 sectorSize
|= (cdData
->u1
.BlockDescriptor
.BlockLength
[1] << 8);
3882 sectorSize
|= (cdData
->u1
.BlockDescriptor
.BlockLength
[2]);
3884 cdData
->RawAccess
= (sectorSize
== RAW_SECTOR_SIZE
) ? TRUE
: FALSE
;
3887 // Free the old data buffer, mdl.
3890 ExFreePool(srb
->DataBuffer
);
3891 IoFreeMdl(Irp
->MdlAddress
);
3898 cdb
= (PCDB
)srb
->Cdb
;
3899 RtlZeroMemory(cdb
, CDB12GENERIC_LENGTH
);
3902 if (cdData
->RawAccess
) {
3904 PRAW_READ_INFO rawReadInfo
=
3905 (PRAW_READ_INFO
)realIrpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
3907 ULONG maximumTransferLength
;
3908 ULONG transferPages
;
3911 // Calculate starting offset.
3914 startingSector
= (ULONG
)(rawReadInfo
->DiskOffset
.QuadPart
>> deviceExtension
->SectorShift
);
3915 transferByteCount
= rawReadInfo
->SectorCount
* RAW_SECTOR_SIZE
;
3916 maximumTransferLength
= deviceExtension
->PortCapabilities
->MaximumTransferLength
;
3917 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(realIrp
->MdlAddress
),
3921 // Determine if request is within limits imposed by miniport.
3922 // If the request is larger than the miniport's capabilities, split it.
3925 if (transferByteCount
> maximumTransferLength
||
3926 transferPages
> deviceExtension
->PortCapabilities
->MaximumPhysicalPages
) {
3928 realIrp
->IoStatus
.Information
= 0;
3929 realIrp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
3930 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
3932 ExFreePool(srb
->SenseInfoBuffer
);
3933 ExFreePool(srb
->DataBuffer
);
3935 IoFreeMdl(Irp
->MdlAddress
);
3938 IoStartNextPacket(DeviceObject
, FALSE
);
3940 return STATUS_MORE_PROCESSING_REQUIRED
;
3943 srb
->OriginalRequest
= realIrp
;
3944 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
3945 srb
->SrbFlags
|= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
);
3946 srb
->DataTransferLength
= transferByteCount
;
3947 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
3948 srb
->CdbLength
= 10;
3949 srb
->DataBuffer
= MmGetMdlVirtualAddress(realIrp
->MdlAddress
);
3951 if (rawReadInfo
->TrackMode
== CDDA
) {
3952 if (cdData
->XAFlags
& PLEXTOR_CDDA
) {
3954 srb
->CdbLength
= 12;
3956 cdb
->PLXTR_READ_CDDA
.LogicalUnitNumber
= deviceExtension
->Lun
;
3957 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
3958 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
3959 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
3960 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
3962 cdb
->PLXTR_READ_CDDA
.TransferBlockByte3
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
3963 cdb
->PLXTR_READ_CDDA
.TransferBlockByte2
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
3964 cdb
->PLXTR_READ_CDDA
.TransferBlockByte1
= 0;
3965 cdb
->PLXTR_READ_CDDA
.TransferBlockByte0
= 0;
3967 cdb
->PLXTR_READ_CDDA
.SubCode
= 0;
3968 cdb
->PLXTR_READ_CDDA
.OperationCode
= 0xD8;
3970 } else if (cdData
->XAFlags
& NEC_CDDA
) {
3972 cdb
->NEC_READ_CDDA
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
3973 cdb
->NEC_READ_CDDA
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
3974 cdb
->NEC_READ_CDDA
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
3975 cdb
->NEC_READ_CDDA
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
3977 cdb
->NEC_READ_CDDA
.TransferBlockByte1
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
3978 cdb
->NEC_READ_CDDA
.TransferBlockByte0
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
3980 cdb
->NEC_READ_CDDA
.OperationCode
= 0xD4;
3983 cdb
->CDB10
.LogicalUnitNumber
= deviceExtension
->Lun
;
3985 cdb
->CDB10
.TransferBlocksMsb
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
3986 cdb
->CDB10
.TransferBlocksLsb
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
3988 cdb
->CDB10
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
3989 cdb
->CDB10
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
3990 cdb
->CDB10
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
3991 cdb
->CDB10
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
3993 cdb
->CDB10
.OperationCode
= SCSIOP_READ
;
3996 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
3999 irpStack
= IoGetNextIrpStackLocation(realIrp
);
4000 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
4001 irpStack
->Parameters
.Scsi
.Srb
= srb
;
4003 if (!(irpStack
->Parameters
.Others
.Argument1
)) {
4006 // Only jam this in if it doesn't exist. The completion routines can
4007 // call StartIo directly in the case of retries and resetting it will
4008 // cause infinite loops.
4011 irpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
4015 // Set up IoCompletion routine address.
4018 IoSetCompletionRoutine(realIrp
,
4026 ULONG maximumTransferLength
= deviceExtension
->PortCapabilities
->MaximumTransferLength
;
4027 ULONG transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(realIrp
->MdlAddress
),
4028 realIrpStack
->Parameters
.Read
.Length
);
4030 // Back to cooked sectors. Build and send a normal read.
4031 // The real work for setting offsets and checking for splitrequests was
4035 if ((realIrpStack
->Parameters
.Read
.Length
> maximumTransferLength
) ||
4036 (transferPages
> deviceExtension
->PortCapabilities
->MaximumPhysicalPages
)) {
4039 // Request needs to be split. Completion of each portion of the request will
4040 // fire off the next portion. The final request will signal Io to send a new request.
4043 ScsiClassSplitRequest(DeviceObject
, realIrp
, maximumTransferLength
);
4044 return STATUS_MORE_PROCESSING_REQUIRED
;
4049 // Build SRB and CDB for this IRP.
4052 ScsiClassBuildRequest(DeviceObject
, realIrp
);
4058 // Call the port driver.
4061 IoCallDriver(deviceExtension
->PortDeviceObject
, realIrp
);
4063 return STATUS_MORE_PROCESSING_REQUIRED
;
4067 // Update device Extension flags to indicate that XA isn't supported.
4070 cdData
->XAFlags
|= XA_NOT_SUPPORTED
;
4073 // Deallocate srb and sense buffer.
4077 if (srb
->DataBuffer
) {
4078 ExFreePool(srb
->DataBuffer
);
4080 if (srb
->SenseInfoBuffer
) {
4081 ExFreePool(srb
->SenseInfoBuffer
);
4086 if (Irp
->PendingReturned
) {
4087 IoMarkIrpPending(Irp
);
4090 if (realIrp
->PendingReturned
) {
4091 IoMarkIrpPending(realIrp
);
4094 if (Irp
->MdlAddress
) {
4095 IoFreeMdl(Irp
->MdlAddress
);
4101 // Set status in completing IRP.
4104 realIrp
->IoStatus
.Status
= status
;
4107 // Set the hard error if necessary.
4110 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
4113 // Store DeviceObject for filesystem, and clear
4114 // in IoStatus.Information field.
4117 IoSetHardErrorOrVerifyDevice(realIrp
, DeviceObject
);
4118 realIrp
->IoStatus
.Information
= 0;
4121 IoCompleteRequest(realIrp
, IO_DISK_INCREMENT
);
4123 IoStartNextPacket(DeviceObject
, FALSE
);
4125 return STATUS_MORE_PROCESSING_REQUIRED
;
4131 IN PDEVICE_OBJECT DeviceObject
,
4138 Routine Description:
4140 This routine executes when the port driver has completed a request.
4141 It looks at the SRB status in the completing SRB and if not success
4142 it checks for valid request sense buffer information. If valid, the
4143 info is used to update status with more precise message of type of
4144 error. This routine deallocates the SRB.
4148 DeviceObject - Supplies the device object which represents the logical
4151 Irp - Supplies the Irp which has completed.
4153 Context - Supplies a pointer to the SRB.
4162 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
4163 PIO_STACK_LOCATION irpNextStack
= IoGetNextIrpStackLocation(Irp
);
4164 PSCSI_REQUEST_BLOCK srb
= Context
;
4169 // Check SRB status for success of completing request.
4172 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
4174 DebugPrint((2,"ScsiClassIoComplete: IRP %lx, SRB %lx\n", Irp
, srb
));
4177 // Release the queue if it is frozen.
4180 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
4181 ScsiClassReleaseQueue(DeviceObject
);
4184 retry
= ScsiClassInterpretSenseInfo(
4187 irpStack
->MajorFunction
,
4188 irpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
? irpStack
->Parameters
.DeviceIoControl
.IoControlCode
: 0,
4189 MAXIMUM_RETRIES
- ((ULONG
)irpNextStack
->Parameters
.Others
.Argument1
),
4193 // If the status is verified required and the this request
4194 // should bypass verify required then retry the request.
4197 if (irpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
4198 status
== STATUS_VERIFY_REQUIRED
) {
4200 status
= STATUS_IO_DEVICE_ERROR
;
4204 if (retry
&& (irpNextStack
->Parameters
.Others
.Argument1
= (ULONG
)irpNextStack
->Parameters
.Others
.Argument1
-1)) {
4206 if (((ULONG
)irpNextStack
->Parameters
.Others
.Argument1
)) {
4212 DebugPrint((1, "CdRomXACompletion: Retry request %lx - Calling StartIo\n", Irp
));
4215 ExFreePool(srb
->SenseInfoBuffer
);
4216 ExFreePool(srb
->DataBuffer
);
4220 // Call StartIo directly since IoStartNextPacket hasn't been called,
4221 // the serialisation is still intact.
4224 ScsiCdRomStartIo(DeviceObject
, Irp
);
4225 return STATUS_MORE_PROCESSING_REQUIRED
;
4230 // Exhausted retries. Fall through and complete the request with the appropriate status.
4236 // Set status for successful request.
4239 status
= STATUS_SUCCESS
;
4241 } // end if (SRB_STATUS(srb->SrbStatus) ...
4244 // Return SRB to nonpaged pool.
4250 // Set status in completing IRP.
4253 Irp
->IoStatus
.Status
= status
;
4256 // Set the hard error if necessary.
4259 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
4262 // Store DeviceObject for filesystem, and clear
4263 // in IoStatus.Information field.
4266 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
4267 Irp
->IoStatus
.Information
= 0;
4271 // If pending has be returned for this irp then mark the current stack as
4275 if (Irp
->PendingReturned
) {
4276 IoMarkIrpPending(Irp
);
4279 //IoCompleteRequest(Irp, IO_DISK_INCREMENT);
4280 IoStartNextPacket(DeviceObject
, FALSE
);
4288 IN PDEVICE_OBJECT DeviceObject
,
4294 Routine Description:
4296 This is the NT device control handler for CDROMs.
4300 DeviceObject - for this CDROM
4302 Irp - IO Request packet
4311 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
4312 PIO_STACK_LOCATION nextStack
;
4313 PKEVENT deviceControlEvent
;
4314 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4315 PCDROM_DATA cdData
= (PCDROM_DATA
)(deviceExtension
+1);
4316 SCSI_REQUEST_BLOCK srb
;
4327 // Zero the SRB on stack.
4330 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
4332 Irp
->IoStatus
.Information
= 0;
4335 // if this is a class driver ioctl then we need to change the base code
4336 // to IOCTL_CDROM_BASE so that the switch statement can handle it.
4338 // WARNING - currently the scsi class ioctl function codes are between
4339 // 0x200 & 0x300. this routine depends on that fact
4342 ioctlCode
= irpStack
->Parameters
.DeviceIoControl
.IoControlCode
;
4343 baseCode
= ioctlCode
>> 16;
4344 functionCode
= (ioctlCode
& (~0xffffc003)) >> 2;
4346 DebugPrint((1, "CdRomDeviceControl: Ioctl Code = %#08lx, Base Code = %#lx,"
4347 " Function Code = %#lx\n",
4353 if((functionCode
>= 0x200) && (functionCode
<= 0x300)) {
4355 ioctlCode
= (ioctlCode
& 0x0000ffff) | CTL_CODE(IOCTL_CDROM_BASE
, 0, 0, 0);
4357 DebugPrint((1, "CdRomDeviceControl: Class Code - new ioctl code is %#08lx\n",
4360 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= ioctlCode
;
4364 switch (ioctlCode
) {
4366 case IOCTL_CDROM_RAW_READ
: {
4368 LARGE_INTEGER startingOffset
;
4369 ULONG transferBytes
;
4370 ULONG startingSector
;
4371 PRAW_READ_INFO rawReadInfo
= (PRAW_READ_INFO
)irpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
4372 PUCHAR userData
= (PUCHAR
)Irp
->AssociatedIrp
.SystemBuffer
;
4375 // Ensure that XA reads are supported.
4378 if (cdData
->XAFlags
& XA_NOT_SUPPORTED
) {
4381 "CdRomDeviceControl: XA Reads not supported. Flags (%x)\n",
4384 status
= STATUS_INVALID_DEVICE_REQUEST
;
4389 // Check that ending sector is on disc and buffers are there and of
4393 if (rawReadInfo
== NULL
) {
4396 // Called from user space. Validate the buffers.
4399 rawReadInfo
= (PRAW_READ_INFO
)userData
;
4400 irpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
= (PVOID
)userData
;
4402 if (rawReadInfo
== NULL
) {
4404 DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (No extent info\n"));
4406 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
4408 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4409 return STATUS_INVALID_PARAMETER
;
4412 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
!= sizeof(RAW_READ_INFO
)) {
4414 DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (Invalid info buffer\n"));
4416 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
4418 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4419 return STATUS_INVALID_PARAMETER
;
4423 startingOffset
.QuadPart
= rawReadInfo
->DiskOffset
.QuadPart
;
4424 startingSector
= (ULONG
)(rawReadInfo
->DiskOffset
.QuadPart
>> deviceExtension
->SectorShift
);
4425 transferBytes
= rawReadInfo
->SectorCount
* RAW_SECTOR_SIZE
;
4427 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< transferBytes
) {
4429 DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (Bad buffer size)\n"));
4432 // Fail request with status of invalid parameters.
4435 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
4437 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4438 return STATUS_INVALID_PARAMETER
;
4441 if ((startingOffset
.QuadPart
+ transferBytes
) > deviceExtension
->PartitionLength
.QuadPart
) {
4443 DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (Request Out of Bounds)\n"));
4446 // Fail request with status of invalid parameters.
4449 status
= STATUS_INVALID_PARAMETER
;
4453 IoMarkIrpPending(Irp
);
4454 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4456 return STATUS_PENDING
;
4459 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
: {
4461 DebugPrint((2,"CdRomDeviceControl: Get drive geometry\n"));
4463 if ( irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
4464 sizeof( DISK_GEOMETRY
) ) {
4466 status
= STATUS_INFO_LENGTH_MISMATCH
;
4470 IoMarkIrpPending(Irp
);
4471 IoStartPacket(DeviceObject
,Irp
, NULL
,NULL
);
4473 return STATUS_PENDING
;
4476 case IOCTL_CDROM_GET_LAST_SESSION
:
4477 case IOCTL_CDROM_READ_TOC
: {
4480 // If the cd is playing music then reject this request.
4483 if (CdRomIsPlayActive(DeviceObject
)) {
4484 Irp
->IoStatus
.Status
= STATUS_DEVICE_BUSY
;
4485 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4486 return STATUS_DEVICE_BUSY
;
4489 IoMarkIrpPending(Irp
);
4490 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4492 return STATUS_PENDING
;
4495 case IOCTL_CDROM_PLAY_AUDIO_MSF
: {
4501 DebugPrint((2,"CdRomDeviceControl: Play audio MSF\n"));
4503 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
4504 sizeof(CDROM_PLAY_AUDIO_MSF
)) {
4507 // Indicate unsuccessful status.
4510 status
= STATUS_BUFFER_TOO_SMALL
;
4514 IoMarkIrpPending(Irp
);
4515 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4517 return STATUS_PENDING
;
4520 case IOCTL_CDROM_SEEK_AUDIO_MSF
: {
4527 DebugPrint((2,"CdRomDeviceControl: Seek audio MSF\n"));
4529 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
4530 sizeof(CDROM_SEEK_AUDIO_MSF
)) {
4533 // Indicate unsuccessful status.
4536 status
= STATUS_BUFFER_TOO_SMALL
;
4539 IoMarkIrpPending(Irp
);
4540 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4542 return STATUS_PENDING
;
4547 case IOCTL_CDROM_PAUSE_AUDIO
: {
4553 DebugPrint((2, "CdRomDeviceControl: Pause audio\n"));
4555 IoMarkIrpPending(Irp
);
4556 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4558 return STATUS_PENDING
;
4563 case IOCTL_CDROM_RESUME_AUDIO
: {
4569 DebugPrint((2, "CdRomDeviceControl: Resume audio\n"));
4571 IoMarkIrpPending(Irp
);
4572 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4574 return STATUS_PENDING
;
4577 case IOCTL_CDROM_READ_Q_CHANNEL
: {
4579 if(irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
4580 sizeof(CDROM_SUB_Q_DATA_FORMAT
)) {
4582 status
= STATUS_BUFFER_TOO_SMALL
;
4583 Irp
->IoStatus
.Information
= 0;
4587 IoMarkIrpPending(Irp
);
4588 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4590 return STATUS_PENDING
;
4593 case IOCTL_CDROM_GET_CONTROL
: {
4595 DebugPrint((2, "CdRomDeviceControl: Get audio control\n"));
4598 // Verify user buffer is large enough for the data.
4601 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
4602 sizeof(CDROM_AUDIO_CONTROL
)) {
4605 // Indicate unsuccessful status and no data transferred.
4608 status
= STATUS_BUFFER_TOO_SMALL
;
4609 Irp
->IoStatus
.Information
= 0;
4614 IoMarkIrpPending(Irp
);
4615 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4617 return STATUS_PENDING
;
4621 case IOCTL_CDROM_GET_VOLUME
: {
4623 DebugPrint((2, "CdRomDeviceControl: Get volume control\n"));
4626 // Verify user buffer is large enough for data.
4629 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
4630 sizeof(VOLUME_CONTROL
)) {
4633 // Indicate unsuccessful status and no data transferred.
4636 status
= STATUS_BUFFER_TOO_SMALL
;
4637 Irp
->IoStatus
.Information
= 0;
4641 IoMarkIrpPending(Irp
);
4642 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4644 return STATUS_PENDING
;
4648 case IOCTL_CDROM_SET_VOLUME
: {
4650 DebugPrint((2, "CdRomDeviceControl: Set volume control\n"));
4652 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
4653 sizeof(VOLUME_CONTROL
)) {
4656 // Indicate unsuccessful status.
4659 status
= STATUS_BUFFER_TOO_SMALL
;
4663 IoMarkIrpPending(Irp
);
4664 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4666 return STATUS_PENDING
;
4670 case IOCTL_CDROM_STOP_AUDIO
: {
4676 DebugPrint((2, "CdRomDeviceControl: Stop audio\n"));
4678 IoMarkIrpPending(Irp
);
4679 IoStartPacket(DeviceObject
,Irp
, NULL
,NULL
);
4681 return STATUS_PENDING
;
4684 case IOCTL_CDROM_CHECK_VERIFY
: {
4685 DebugPrint((1, "CdRomDeviceControl: [%lx] Check Verify\n", Irp
));
4686 IoMarkIrpPending(Irp
);
4688 if((irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
) &&
4689 (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))) {
4691 DebugPrint((1, "CdRomDeviceControl: Check Verify: media count "
4692 "buffer too small\n"));
4694 status
= STATUS_BUFFER_TOO_SMALL
;
4698 IoStartPacket(DeviceObject
,Irp
, NULL
,NULL
);
4700 return STATUS_PENDING
;
4706 // allocate an event and stuff it into our stack location.
4709 deviceControlEvent
= ExAllocatePool(NonPagedPool
, sizeof(KEVENT
));
4711 if(!deviceControlEvent
) {
4713 status
= STATUS_INSUFFICIENT_RESOURCES
;
4717 PIO_STACK_LOCATION currentStack
;
4719 KeInitializeEvent(deviceControlEvent
, NotificationEvent
, FALSE
);
4721 currentStack
= IoGetCurrentIrpStackLocation(Irp
);
4722 nextStack
= IoGetNextIrpStackLocation(Irp
);
4725 // Copy the stack down a notch
4728 *nextStack
= *currentStack
;
4730 IoSetCompletionRoutine(
4732 CdRomClassIoctlCompletion
,
4739 IoSetNextIrpStackLocation(Irp
);
4741 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4742 Irp
->IoStatus
.Information
= 0;
4745 // Override volume verifies on this stack location so that we
4746 // will be forced through the synchronization. Once this location
4747 // goes away we get the old value back
4750 nextStack
->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
4752 IoMarkIrpPending(Irp
);
4754 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
4757 // Wait for CdRomClassIoctlCompletion to set the event. This
4758 // ensures serialization remains intact for these unhandled device
4762 KeWaitForSingleObject(
4769 ExFreePool(deviceControlEvent
);
4771 DebugPrint((2, "CdRomDeviceControl: irp %#08lx synchronized\n", Irp
));
4774 // If an error occured then propagate that back up - we are no longer
4775 // guaranteed synchronization and the upper layers will have to
4778 // If no error occured, call down to the class driver directly
4779 // then start up the next request.
4782 if(Irp
->IoStatus
.Status
== STATUS_SUCCESS
) {
4784 status
= ScsiClassDeviceControl(DeviceObject
, Irp
);
4786 KeRaiseIrql(DISPATCH_LEVEL
, &irql
);
4788 IoStartNextPacket(DeviceObject
, FALSE
);
4799 if (status
== STATUS_VERIFY_REQUIRED
) {
4802 // If the status is verified required and this request
4803 // should bypass verify required then retry the request.
4806 if (irpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
) {
4808 status
= STATUS_IO_DEVICE_ERROR
;
4814 if (IoIsErrorUserInduced(status
)) {
4816 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
4821 // Update IRP with completion status.
4824 Irp
->IoStatus
.Status
= status
;
4827 // Complete the request.
4830 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
4831 DebugPrint((2, "CdRomDeviceControl: Status is %lx\n", status
));
4834 } // end ScsiCdRomDeviceControl()
4839 PDEVICE_OBJECT DeviceObject
,
4840 PINQUIRYDATA InquiryData
,
4841 PIO_SCSI_CAPABILITIES PortCapabilities
4846 Routine Description:
4848 This function checks to see if an SCSI logical unit requires an special
4849 initialization or error processing.
4853 DeviceObject - Supplies the device object to be tested.
4855 InquiryData - Supplies the inquiry data returned by the device of interest.
4857 PortCapabilities - Supplies the capabilities of the device object.
4866 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4867 PCDROM_DATA cdData
= (PCDROM_DATA
)(deviceExtension
+1);
4870 // Look for a Hitachi CDR-1750. Read-ahead must be disabled in order
4871 // to get this cdrom drive to work on scsi adapters that use PIO.
4874 if ((strncmp(InquiryData
->VendorId
, "HITACHI CDR-1750S", strlen("HITACHI CDR-1750S")) == 0 ||
4875 strncmp(InquiryData
->VendorId
, "HITACHI CDR-3650/1650S", strlen("HITACHI CDR-3650/1650S")) == 0)
4876 && PortCapabilities
->AdapterUsesPio
) {
4878 DebugPrint((1, "CdRom ScanForSpecial: Found Hitachi CDR-1750S.\n"));
4881 // Setup an error handler to reinitialize the cd rom after it is reset.
4884 deviceExtension
->ClassError
= HitachProcessError
;
4886 } else if (( RtlCompareMemory( InquiryData
->VendorId
,"FUJITSU", 7 ) == 7 ) &&
4887 (( RtlCompareMemory( InquiryData
->ProductId
,"FMCD-101", 8 ) == 8 ) ||
4888 ( RtlCompareMemory( InquiryData
->ProductId
,"FMCD-102", 8 ) == 8 ))) {
4891 // When Read command is issued to FMCD-101 or FMCD-102 and there is a music
4892 // cd in it. It takes longer time than SCSI_CDROM_TIMEOUT before returning
4896 deviceExtension
->TimeOutValue
= 20;
4898 } else if (( RtlCompareMemory( InquiryData
->VendorId
,"TOSHIBA", 7) == 7) &&
4899 (( RtlCompareMemory( InquiryData
->ProductId
,"CD-ROM XM-34", 12) == 12))) {
4901 SCSI_REQUEST_BLOCK srb
;
4908 // Set the density code and the error handler.
4911 length
= (sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH
);
4913 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
4916 // Build the MODE SENSE CDB.
4920 cdb
= (PCDB
)srb
.Cdb
;
4923 // Set timeout value from device extension.
4926 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
4928 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
4929 cdb
->MODE_SENSE
.PageCode
= 0x1;
4930 cdb
->MODE_SENSE
.AllocationLength
= (UCHAR
)length
;
4932 buffer
= ExAllocatePool(NonPagedPoolCacheAligned
, (sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH
));
4937 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
4943 ((PERROR_RECOVERY_DATA
)buffer
)->BlockDescriptor
.DensityCode
= 0x83;
4944 ((PERROR_RECOVERY_DATA
)buffer
)->Header
.ModeDataLength
= 0x0;
4946 RtlCopyMemory(&cdData
->u1
.Header
, buffer
, sizeof(ERROR_RECOVERY_DATA
));
4948 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
4951 // Build the MODE SENSE CDB.
4955 cdb
= (PCDB
)srb
.Cdb
;
4958 // Set timeout value from device extension.
4961 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
4963 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
4964 cdb
->MODE_SELECT
.PFBit
= 1;
4965 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)length
;
4967 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
4973 if (!NT_SUCCESS(status
)) {
4975 "Cdrom.ScanForSpecial: Setting density code on Toshiba failed [%x]\n",
4979 deviceExtension
->ClassError
= ToshibaProcessError
;
4986 // Determine special CD-DA requirements.
4989 if (RtlCompareMemory( InquiryData
->VendorId
,"PLEXTOR",7) == 7) {
4990 cdData
->XAFlags
|= PLEXTOR_CDDA
;
4991 } else if (RtlCompareMemory ( InquiryData
->VendorId
,"NEC",3) == 3) {
4992 cdData
->XAFlags
|= NEC_CDDA
;
5001 PDEVICE_OBJECT DeviceObject
,
5002 PSCSI_REQUEST_BLOCK Srb
,
5008 Routine Description:
5010 This routine checks the type of error. If the error indicates CD-ROM the
5011 CD-ROM needs to be reinitialized then a Mode sense command is sent to the
5012 device. This command disables read-ahead for the device.
5016 DeviceObject - Supplies a pointer to the device object.
5018 Srb - Supplies a pointer to the failing Srb.
5031 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
5032 PSENSE_DATA senseBuffer
= Srb
->SenseInfoBuffer
;
5033 LARGE_INTEGER largeInt
;
5035 PIO_STACK_LOCATION irpStack
;
5037 PSCSI_REQUEST_BLOCK srb
;
5038 PCOMPLETION_CONTEXT context
;
5042 UNREFERENCED_PARAMETER(Status
);
5043 UNREFERENCED_PARAMETER(Retry
);
5045 largeInt
.QuadPart
= (LONGLONG
) 1;
5048 // Check the status. The initialization command only needs to be sent
5049 // if UNIT ATTENTION is returned.
5052 if (!(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
)) {
5055 // The drive does not require reinitialization.
5062 // Found a bad HITACHI cd-rom. These devices do not work with PIO
5063 // adapters when read-ahead is enabled. Read-ahead is disabled by
5064 // a mode select command. The mode select page code is zero and the
5065 // length is 6 bytes. All of the other bytes should be zero.
5069 if ((senseBuffer
->SenseKey
& 0xf) == SCSI_SENSE_UNIT_ATTENTION
) {
5071 DebugPrint((1, "HitachiProcessError: Reinitializing the CD-ROM.\n"));
5074 // Send the special mode select command to disable read-ahead
5075 // on the CD-ROM reader.
5078 alignment
= DeviceObject
->AlignmentRequirement
?
5079 DeviceObject
->AlignmentRequirement
: 1;
5081 context
= ExAllocatePool(
5083 sizeof(COMPLETION_CONTEXT
) + HITACHI_MODE_DATA_SIZE
+ alignment
5086 if (context
== NULL
) {
5089 // If there is not enough memory to fulfill this request,
5090 // simply return. A subsequent retry will fail and another
5091 // chance to start the unit.
5097 context
->DeviceObject
= DeviceObject
;
5098 srb
= &context
->Srb
;
5100 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
5103 // Write length to SRB.
5106 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
5109 // Set up SCSI bus address.
5112 srb
->PathId
= deviceExtension
->PathId
;
5113 srb
->TargetId
= deviceExtension
->TargetId
;
5114 srb
->Lun
= deviceExtension
->Lun
;
5116 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
5117 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
5120 // Set the transfer length.
5123 srb
->DataTransferLength
= HITACHI_MODE_DATA_SIZE
;
5124 srb
->SrbFlags
= SRB_FLAGS_DATA_OUT
| SRB_FLAGS_DISABLE_AUTOSENSE
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
5127 // The data buffer must be aligned.
5130 srb
->DataBuffer
= (PVOID
) (((ULONG
) (context
+ 1) + (alignment
- 1)) &
5135 // Build the HITACHI read-ahead mode select CDB.
5139 cdb
= (PCDB
)srb
->Cdb
;
5140 cdb
->MODE_SENSE
.LogicalUnitNumber
= srb
->Lun
;
5141 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SELECT
;
5142 cdb
->MODE_SENSE
.AllocationLength
= HITACHI_MODE_DATA_SIZE
;
5145 // Initialize the mode sense data.
5148 modePage
= srb
->DataBuffer
;
5150 RtlZeroMemory(modePage
, HITACHI_MODE_DATA_SIZE
);
5153 // Set the page length field to 6.
5159 // Build the asynchronous request to be sent to the port driver.
5162 irp
= IoBuildAsynchronousFsdRequest(IRP_MJ_WRITE
,
5165 srb
->DataTransferLength
,
5169 IoSetCompletionRoutine(irp
,
5170 (PIO_COMPLETION_ROUTINE
)ScsiClassAsynchronousCompletion
,
5176 irpStack
= IoGetNextIrpStackLocation(irp
);
5178 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
5180 srb
->OriginalRequest
= irp
;
5183 // Save SRB address in next stack for port driver.
5186 irpStack
->Parameters
.Scsi
.Srb
= (PVOID
)srb
;
5189 // Set up IRP Address.
5192 (VOID
)IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
5199 ToshibaProcessErrorCompletion(
5200 PDEVICE_OBJECT DeviceObject
,
5207 Routine Description:
5209 Completion routine for the ClassError routine to handle older Toshiba units
5210 that require setting the density code.
5214 DeviceObject - Supplies a pointer to the device object.
5216 Irp - Pointer to irp created to set the density code.
5218 Context - Supplies a pointer to the Mode Select Srb.
5223 STATUS_MORE_PROCESSING_REQUIRED
5229 PSCSI_REQUEST_BLOCK srb
= Context
;
5232 // Check for a frozen queue.
5235 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
5238 // Unfreeze the queue getting the device object from the context.
5241 ScsiClassReleaseQueue(DeviceObject
);
5245 // Free all of the allocations.
5248 ExFreePool(srb
->DataBuffer
);
5250 IoFreeMdl(Irp
->MdlAddress
);
5254 // Indicate the I/O system should stop processing the Irp completion.
5257 return STATUS_MORE_PROCESSING_REQUIRED
;
5262 ToshibaProcessError(
5263 PDEVICE_OBJECT DeviceObject
,
5264 PSCSI_REQUEST_BLOCK Srb
,
5271 Routine Description:
5273 This routine checks the type of error. If the error indicates a unit attention,
5274 the density code needs to be set via a Mode select command.
5278 DeviceObject - Supplies a pointer to the device object.
5280 Srb - Supplies a pointer to the failing Srb.
5293 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
5294 PCDROM_DATA cdData
= (PCDROM_DATA
)(deviceExtension
+1);
5295 PSENSE_DATA senseBuffer
= Srb
->SenseInfoBuffer
;
5296 PIO_STACK_LOCATION irpStack
;
5298 PSCSI_REQUEST_BLOCK srb
;
5304 if (!(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
)) {
5309 // The Toshiba's require the density code to be set on power up and media changes.
5312 if ((senseBuffer
->SenseKey
& 0xf) == SCSI_SENSE_UNIT_ATTENTION
) {
5315 irp
= IoAllocateIrp((CCHAR
)(deviceExtension
->DeviceObject
->StackSize
+1),
5322 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
5329 length
= sizeof(ERROR_RECOVERY_DATA
);
5330 dataBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, length
);
5337 irp
->MdlAddress
= IoAllocateMdl(dataBuffer
,
5343 if (!irp
->MdlAddress
) {
5345 ExFreePool(dataBuffer
);
5354 MmBuildMdlForNonPagedPool(irp
->MdlAddress
);
5356 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
5358 srb
->DataBuffer
= dataBuffer
;
5359 cdb
= (PCDB
)srb
->Cdb
;
5365 IoSetNextIrpStackLocation(irp
);
5366 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
5367 irp
->IoStatus
.Information
= 0;
5369 irp
->UserBuffer
= NULL
;
5372 // Save the device object and irp in a private stack location.
5375 irpStack
= IoGetCurrentIrpStackLocation(irp
);
5376 irpStack
->DeviceObject
= deviceExtension
->DeviceObject
;
5379 // Construct the IRP stack for the lower level driver.
5382 irpStack
= IoGetNextIrpStackLocation(irp
);
5383 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
5384 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_OUT
;
5385 irpStack
->Parameters
.Scsi
.Srb
= srb
;
5387 IoSetCompletionRoutine(irp
,
5388 ToshibaProcessErrorCompletion
,
5394 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
5395 srb
->PathId
= deviceExtension
->PathId
;
5396 srb
->TargetId
= deviceExtension
->TargetId
;
5397 srb
->Lun
= deviceExtension
->Lun
;
5398 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
5399 srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
5400 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
5402 srb
->OriginalRequest
= irp
;
5403 srb
->SenseInfoBufferLength
= 0;
5406 // Set the transfer length.
5409 srb
->DataTransferLength
= length
;
5410 srb
->SrbFlags
= SRB_FLAGS_DATA_OUT
| SRB_FLAGS_DISABLE_AUTOSENSE
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
5414 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
5415 cdb
->MODE_SELECT
.PFBit
= 1;
5416 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)length
;
5419 // Copy the Mode page into the databuffer.
5422 RtlCopyMemory(srb
->DataBuffer
, &cdData
->u1
.Header
, length
);
5425 // Set the density code.
5428 ((PERROR_RECOVERY_DATA
)srb
->DataBuffer
)->BlockDescriptor
.DensityCode
= 0x83;
5430 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
5437 IN PDEVICE_OBJECT DeviceObject
5442 Routine Description:
5444 This routine determines if the cd is currently playing music.
5448 DeviceObject - Device object to test.
5452 TRUE if the device is playing music.
5456 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
5458 IO_STATUS_BLOCK ioStatus
;
5461 PSUB_Q_CURRENT_POSITION currentBuffer
;
5463 if (!PLAY_ACTIVE(deviceExtension
)) {
5467 currentBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, sizeof(SUB_Q_CURRENT_POSITION
));
5469 if (currentBuffer
== NULL
) {
5473 ((PCDROM_SUB_Q_DATA_FORMAT
) currentBuffer
)->Format
= IOCTL_CDROM_CURRENT_POSITION
;
5474 ((PCDROM_SUB_Q_DATA_FORMAT
) currentBuffer
)->Track
= 0;
5477 // Create notification event object to be used to signal the
5478 // request completion.
5481 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
5484 // Build the synchronous request to be sent to the port driver
5485 // to perform the request.
5488 irp
= IoBuildDeviceIoControlRequest(IOCTL_CDROM_READ_Q_CHANNEL
,
5489 deviceExtension
->DeviceObject
,
5491 sizeof(CDROM_SUB_Q_DATA_FORMAT
),
5493 sizeof(SUB_Q_CURRENT_POSITION
),
5499 ExFreePool(currentBuffer
);
5504 // Pass request to port driver and wait for request to complete.
5507 status
= IoCallDriver(deviceExtension
->DeviceObject
, irp
);
5509 if (status
== STATUS_PENDING
) {
5510 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
5511 status
= ioStatus
.Status
;
5514 if (!NT_SUCCESS(status
)) {
5515 ExFreePool(currentBuffer
);
5519 ExFreePool(currentBuffer
);
5521 return(PLAY_ACTIVE(deviceExtension
));
5525 IO_COMPLETION_ROUTINE CdRomMediaChangeCompletion
;
5528 CdRomMediaChangeCompletion(
5529 PDEVICE_OBJECT DeviceObject
,
5536 Routine Description:
5538 This routine handles the completion of the test unit ready irps
5539 used to determine if the media has changed. If the media has
5540 changed, this code signals the named event to wake up other
5541 system services that react to media change (aka AutoPlay).
5545 DeviceObject - the object for the completion
5546 Irp - the IRP being completed
5547 Context - the SRB from the IRP
5556 PSCSI_REQUEST_BLOCK srb
= (PSCSI_REQUEST_BLOCK
) Context
;
5557 PIO_STACK_LOCATION cdStack
= IoGetCurrentIrpStackLocation(Irp
);
5558 PIO_STACK_LOCATION irpNextStack
= IoGetNextIrpStackLocation(Irp
);
5559 PDEVICE_EXTENSION deviceExtension
;
5560 PDEVICE_EXTENSION physicalExtension
;
5561 PSENSE_DATA senseBuffer
;
5566 DeviceObject
= cdStack
->DeviceObject
;
5567 ASSERT(DeviceObject
);
5569 deviceExtension
= DeviceObject
->DeviceExtension
;
5570 physicalExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
5571 cddata
= (PCDROM_DATA
)(deviceExtension
+ 1);
5573 ASSERT(cddata
->MediaChangeIrp
== NULL
);
5576 // If the sense data field is valid, look for a media change.
5577 // otherwise this iteration of the polling will just assume nothing
5581 DebugPrint((3, "CdRomMediaChangeHandler: Completing Autorun Irp 0x%lx "
5583 Irp
, deviceExtension
->DeviceNumber
));
5585 if (srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) {
5586 if (srb
->SenseInfoBufferLength
>= FIELD_OFFSET(SENSE_DATA
, CommandSpecificInformation
)) {
5589 // See if this is a media change.
5592 senseBuffer
= srb
->SenseInfoBuffer
;
5593 if ((senseBuffer
->SenseKey
& 0x0f) == SCSI_SENSE_UNIT_ATTENTION
) {
5594 if (senseBuffer
->AdditionalSenseCode
== SCSI_ADSENSE_MEDIUM_CHANGED
) {
5596 DebugPrint((1, "CdRomMediaChangeCompletion: New media inserted "
5597 "into CdRom%d [irp = 0x%lx]\n",
5598 deviceExtension
->DeviceNumber
, Irp
));
5601 // Media change event occurred - signal the named event.
5604 KeSetEvent(deviceExtension
->MediaChangeEvent
,
5608 deviceExtension
->MediaChangeNoMedia
= FALSE
;
5612 if (DeviceObject
->Vpb
->Flags
& VPB_MOUNTED
) {
5615 // Must remember the media changed and force the
5616 // file system to verify on next access
5619 DeviceObject
->Flags
|= DO_VERIFY_VOLUME
;
5622 physicalExtension
->MediaChangeCount
++;
5624 } else if(((senseBuffer
->SenseKey
& 0x0f) == SCSI_SENSE_NOT_READY
)&&
5625 (senseBuffer
->AdditionalSenseCode
== SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
)&&
5626 (!deviceExtension
->MediaChangeNoMedia
)){
5629 // If there was no media in the device then signal the waiters if
5630 // we haven't already done so before.
5633 DebugPrint((1, "CdRomMediaChangeCompletion: No media in device"
5634 "CdRom%d [irp = 0x%lx]\n",
5635 deviceExtension
->DeviceNumber
, Irp
));
5637 KeSetEvent(deviceExtension
->MediaChangeEvent
,
5641 deviceExtension
->MediaChangeNoMedia
= TRUE
;
5645 } else if((srb
->SrbStatus
== SRB_STATUS_SUCCESS
)&&
5646 (deviceExtension
->MediaChangeNoMedia
)) {
5648 // We didn't have any media before and now the requests are succeeding
5649 // we probably missed the Media change somehow. Signal the change
5653 DebugPrint((1, "CdRomMediaChangeCompletion: Request completed normally"
5654 "for CdRom%d which was marked w/NoMedia [irp = 0x%lx]\n",
5655 deviceExtension
->DeviceNumber
, Irp
));
5657 KeSetEvent(deviceExtension
->MediaChangeEvent
,
5661 deviceExtension
->MediaChangeNoMedia
= FALSE
;
5665 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
5666 ScsiClassReleaseQueue(deviceExtension
->DeviceObject
);
5670 // Remember the IRP and SRB for use the next time.
5673 irpNextStack
->Parameters
.Scsi
.Srb
= srb
;
5674 cddata
->MediaChangeIrp
= Irp
;
5676 if (deviceExtension
->ClassError
) {
5682 // Throw away the status and retry values. Just give the error routine a chance
5683 // to do what it needs to.
5686 deviceExtension
->ClassError(DeviceObject
,
5692 IoStartNextPacket(DeviceObject
, FALSE
);
5694 return STATUS_MORE_PROCESSING_REQUIRED
;
5700 IN PDEVICE_OBJECT DeviceObject
,
5706 Routine Description:
5708 This routine handles the once per second timer provided by the
5709 Io subsystem. It is only used when the cdrom device itself is
5710 a candidate for autoplay support. It should never be called if
5711 the cdrom device is a changer device.
5715 DeviceObject - what to check.
5728 PLIST_ENTRY listEntry
;
5730 PIO_STACK_LOCATION irpStack
;
5731 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
5733 cddata
= (PCDROM_DATA
)(deviceExtension
+ 1);
5735 if (cddata
->MediaChange
) {
5736 if (cddata
->MediaChangeIrp
!= NULL
) {
5739 // Media change support is active and the IRP is waiting.
5740 // Decrement the timer.
5741 // There is no MP protection on the timer counter. This
5742 // code is the only code that will manipulate the timer
5743 // and only one instance of it should be running at any
5747 cddata
->MediaChangeCountDown
--;
5750 cddata
->MediaChangeIrpTimeInUse
= 0;
5751 cddata
->MediaChangeIrpLost
= FALSE
;
5754 if (!cddata
->MediaChangeCountDown
) {
5755 PSCSI_REQUEST_BLOCK srb
;
5756 PIO_STACK_LOCATION irpNextStack
;
5763 cddata
->MediaChangeCountDown
= MEDIA_CHANGE_DEFAULT_TIME
;
5766 // Prepare the IRP for the test unit ready
5769 irp
= cddata
->MediaChangeIrp
;
5770 cddata
->MediaChangeIrp
= NULL
;
5772 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
5773 irp
->IoStatus
.Information
= 0;
5775 irp
->UserBuffer
= NULL
;
5778 // If the irp is sent down when the volume needs to be
5779 // verified, CdRomUpdateGeometryCompletion won't complete
5780 // it since it's not associated with a thread. Marking
5781 // it to override the verify causes it always be sent
5782 // to the port driver
5785 irpStack
= IoGetCurrentIrpStackLocation(irp
);
5786 irpStack
->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
5788 irpNextStack
= IoGetNextIrpStackLocation(irp
);
5789 irpNextStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
5790 irpNextStack
->Parameters
.DeviceIoControl
.IoControlCode
=
5791 IOCTL_SCSI_EXECUTE_NONE
;
5794 // Prepare the SRB for execution.
5797 srb
= irpNextStack
->Parameters
.Scsi
.Srb
;
5798 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
5800 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
5801 srb
->PathId
= deviceExtension
->PathId
;
5802 srb
->TargetId
= deviceExtension
->TargetId
;
5803 srb
->Lun
= deviceExtension
->Lun
;
5804 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
5805 srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
|
5806 SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
5807 srb
->DataTransferLength
= 0;
5808 srb
->OriginalRequest
= irp
;
5810 RtlZeroMemory(srb
->SenseInfoBuffer
, SENSE_BUFFER_SIZE
);
5811 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
5813 cdb
= (PCDB
) &srb
->Cdb
[0];
5814 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_TEST_UNIT_READY
;
5815 cdb
->CDB6GENERIC
.LogicalUnitNumber
= srb
->Lun
;
5818 // Setup the IRP to perform a test unit ready.
5821 IoSetCompletionRoutine(irp
,
5822 CdRomMediaChangeCompletion
,
5829 // Issue the request.
5832 IoStartPacket(DeviceObject
, irp
, NULL
, NULL
);
5837 if(cddata
->MediaChangeIrpLost
== FALSE
) {
5838 if(cddata
->MediaChangeIrpTimeInUse
++ >
5839 MEDIA_CHANGE_TIMEOUT_TIME
) {
5841 DebugPrint((0, "CdRom%d: AutoPlay has lost it's irp and "
5842 "doesn't know where to find it. Leave it "
5843 "alone and it'll come home dragging it's "
5844 "stack behind it.\n",
5845 deviceExtension
->DeviceNumber
));
5846 cddata
->MediaChangeIrpLost
= TRUE
;
5855 // Process all generic timer IRPS in the timer list. As IRPs are pulled
5856 // off of the TimerIrpList they must be remembered in the first loop
5857 // if they are not sent to the lower driver. After all items have
5858 // been pulled off the list, it is possible to put the held IRPs back
5859 // into the TimerIrpList.
5863 if (IsListEmpty(&cddata
->TimerIrpList
)) {
5866 listEntry
= ExInterlockedRemoveHeadList(&cddata
->TimerIrpList
,
5867 &cddata
->TimerIrpSpinLock
);
5872 // There is something in the timer list. Pick up the IRP and
5873 // see if it is ready to be submitted.
5876 irp
= CONTAINING_RECORD(listEntry
, IRP
, Tail
.Overlay
.ListEntry
);
5877 irpStack
= IoGetCurrentIrpStackLocation(irp
);
5879 if (irpStack
->Parameters
.Others
.Argument3
) {
5883 // Decrement the countdown timer and put the IRP back in the list.
5886 count
= (ULONG
) irpStack
->Parameters
.Others
.Argument3
;
5888 irpStack
->Parameters
.Others
.Argument3
= (PVOID
) count
;
5890 ASSERT(irp
->AssociatedIrp
.MasterIrp
== NULL
);
5892 irp
->AssociatedIrp
.MasterIrp
= (PVOID
) heldIrpList
;
5899 // Submit this IRP to the lower driver. This IRP does not
5900 // need to be remembered here. It will be handled again when
5904 DebugPrint((1, "CdRomTickHandler: Reissuing request %lx (thread = %lx)\n", irp
, irp
->Tail
.Overlay
.Thread
));
5907 // feed this to the appropriate port driver
5910 IoCallDriver (deviceExtension
->PortDeviceObject
, irp
);
5915 // Pick up the next IRP from the timer list.
5918 listEntry
= ExInterlockedRemoveHeadList(&cddata
->TimerIrpList
,
5919 &cddata
->TimerIrpSpinLock
);
5923 // Move all held IRPs back onto the timer list.
5926 while (heldIrpList
) {
5929 // Save the single list pointer before queueing this IRP.
5932 nextIrp
= (PIRP
) heldIrpList
->AssociatedIrp
.MasterIrp
;
5933 heldIrpList
->AssociatedIrp
.MasterIrp
= NULL
;
5936 // Return the held IRP to the timer list.
5939 ExInterlockedInsertTailList(&cddata
->TimerIrpList
,
5940 &heldIrpList
->Tail
.Overlay
.ListEntry
,
5941 &cddata
->TimerIrpSpinLock
);
5944 // Continue processing the held IRPs
5947 heldIrpList
= nextIrp
;
5953 CdRomCheckRegistryForMediaChangeValue(
5954 IN PUNICODE_STRING RegistryPath
,
5955 IN ULONG DeviceNumber
5960 Routine Description:
5962 The user must specify that AutoPlay is to run on the platform
5963 by setting the registry value HKEY_LOCAL_MACHINE\System\CurrentControlSet\
5964 Services\Cdrom\Autorun:REG_DWORD:1.
5966 The user can override the global setting to enable or disable Autorun on a
5967 specific cdrom device by setting the key HKEY_LOCAL_MACHINE\System\
5968 CurrentControlSet\Services\Cdrom\Device<N>\Autorun:REG_DWORD to one or zero.
5969 (CURRENTLY UNIMPLEMENTED)
5971 If this registry value does not exist or contains the value zero then
5972 the timer to check for media change does not run.
5976 RegistryPath - pointer to the unicode string inside
5977 ...\CurrentControlSet\Services\Cdrom
5978 DeviceNumber - The number of the device object
5982 TRUE - Autorun is enabled.
5988 #define ITEMS_TO_QUERY 2 /* always 1 greater than what is searched */
5989 PRTL_QUERY_REGISTRY_TABLE parameters
= NULL
;
5997 ANSI_STRING paramNum
;
5999 UNICODE_STRING paramStr
;
6001 UNICODE_STRING paramSuffix
;
6002 UNICODE_STRING paramPath
;
6003 UNICODE_STRING paramDevPath
;
6006 // First append \Parameters to the passed in registry path
6009 RtlInitUnicodeString(¶mStr
, L
"\\Parameters");
6011 RtlInitUnicodeString(¶mPath
, NULL
);
6013 paramPath
.MaximumLength
= RegistryPath
->Length
+
6017 paramPath
.Buffer
= ExAllocatePool(PagedPool
, paramPath
.MaximumLength
);
6019 if(!paramPath
.Buffer
) {
6021 DebugPrint((1,"CdRomCheckRegAP: couldn't allocate paramPath\n"));
6026 RtlZeroMemory(paramPath
.Buffer
, paramPath
.MaximumLength
);
6027 RtlAppendUnicodeToString(¶mPath
, RegistryPath
->Buffer
);
6028 RtlAppendUnicodeToString(¶mPath
, paramStr
.Buffer
);
6030 DebugPrint((2, "CdRomCheckRegAP: paramPath [%d] = %ws\n",
6035 // build a counted ANSI string that contains
6036 // the suffix for the path
6039 sprintf(buf
, "\\Device%lu", DeviceNumber
);
6040 RtlInitAnsiString(¶mNum
, buf
);
6043 // Next convert this into a unicode string
6046 status
= RtlAnsiStringToUnicodeString(¶mSuffix
, ¶mNum
, TRUE
);
6048 if(!NT_SUCCESS(status
)) {
6049 DebugPrint((1,"CdRomCheckRegAP: couldn't convert paramNum to paramSuffix\n"));
6050 ExFreePool(paramPath
.Buffer
);
6054 RtlInitUnicodeString(¶mDevPath
, NULL
);
6057 // now build the device specific path
6060 paramDevPath
.MaximumLength
= paramPath
.Length
+
6061 paramSuffix
.Length
+
6063 paramDevPath
.Buffer
= ExAllocatePool(PagedPool
, paramDevPath
.MaximumLength
);
6065 if(!paramDevPath
.Buffer
) {
6066 RtlFreeUnicodeString(¶mSuffix
);
6067 ExFreePool(paramPath
.Buffer
);
6071 RtlZeroMemory(paramDevPath
.Buffer
, paramDevPath
.MaximumLength
);
6072 RtlAppendUnicodeToString(¶mDevPath
, paramPath
.Buffer
);
6073 RtlAppendUnicodeToString(¶mDevPath
, paramSuffix
.Buffer
);
6075 DebugPrint((2, "CdRomCheckRegAP: paramDevPath [%d] = %ws\n",
6079 parameters
= ExAllocatePool(NonPagedPool
,
6080 sizeof(RTL_QUERY_REGISTRY_TABLE
)*ITEMS_TO_QUERY
);
6085 // Check for the Autorun value.
6088 RtlZeroMemory(parameters
,
6089 (sizeof(RTL_QUERY_REGISTRY_TABLE
)*ITEMS_TO_QUERY
));
6091 parameters
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
6092 parameters
[0].Name
= L
"Autorun";
6093 parameters
[0].EntryContext
= &doRun
;
6094 parameters
[0].DefaultType
= REG_DWORD
;
6095 parameters
[0].DefaultData
= &zero
;
6096 parameters
[0].DefaultLength
= sizeof(ULONG
);
6098 status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
| RTL_REGISTRY_OPTIONAL
,
6099 RegistryPath
->Buffer
,
6104 DebugPrint((2, "CdRomCheckRegAP: cdrom/Autorun flag = %d\n", doRun
));
6106 RtlZeroMemory(parameters
,
6107 (sizeof(RTL_QUERY_REGISTRY_TABLE
)*ITEMS_TO_QUERY
));
6109 parameters
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
6110 parameters
[0].Name
= L
"Autorun";
6111 parameters
[0].EntryContext
= &tmp
;
6112 parameters
[0].DefaultType
= REG_DWORD
;
6113 parameters
[0].DefaultData
= &doRun
;
6114 parameters
[0].DefaultLength
= sizeof(ULONG
);
6116 status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
| RTL_REGISTRY_OPTIONAL
,
6122 DebugPrint((2, "CdRomCheckRegAP: cdrom/parameters/autorun flag = %d\n", tmp
));
6124 RtlZeroMemory(parameters
,
6125 (sizeof(RTL_QUERY_REGISTRY_TABLE
) * ITEMS_TO_QUERY
));
6127 parameters
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
6128 parameters
[0].Name
= L
"Autorun";
6129 parameters
[0].EntryContext
= &doRun
;
6130 parameters
[0].DefaultType
= REG_DWORD
;
6131 parameters
[0].DefaultData
= &tmp
;
6132 parameters
[0].DefaultLength
= sizeof(ULONG
);
6134 status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
| RTL_REGISTRY_OPTIONAL
,
6135 paramDevPath
.Buffer
,
6140 DebugPrint((1, "CdRomCheckRegAP: cdrom/parameters/device%d/autorun flag = %d\n", DeviceNumber
, doRun
));
6142 ExFreePool(parameters
);
6146 ExFreePool(paramPath
.Buffer
);
6147 ExFreePool(paramDevPath
.Buffer
);
6148 RtlFreeUnicodeString(¶mSuffix
);
6150 DebugPrint((1, "CdRomCheckRegAP: Autoplay for device %d is %s\n",
6152 (doRun
? "on" : "off")));
6165 IN PDEVICE_OBJECT DeviceObject
,
6172 Routine Description:
6174 This routine is called by DriverEntry to determine whether a Sanyo 3-CD
6175 changer device is present.
6179 DeviceObject - Supplies the device object for the 'real' device.
6185 TRUE - if an Atapi changer device is found.
6192 PCHAR inquiryBuffer
;
6193 IO_STATUS_BLOCK ioStatus
;
6195 PSCSI_ADAPTER_BUS_INFO adapterInfo
;
6197 PINQUIRYDATA inquiryData
;
6198 PSCSI_INQUIRY_DATA lunInfo
;
6200 inquiryBuffer
= ExAllocatePool(NonPagedPool
, 2048);
6201 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
6202 irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA
,
6215 status
= IoCallDriver(DeviceObject
, irp
);
6217 if (status
== STATUS_PENDING
) {
6218 KeWaitForSingleObject(&event
, Executive
, KernelMode
, FALSE
, NULL
);
6219 status
= ioStatus
.Status
;
6222 if (!NT_SUCCESS(status
)) {
6226 adapterInfo
= (PVOID
) inquiryBuffer
;
6228 for (scsiBus
=0; scsiBus
< (ULONG
)adapterInfo
->NumberOfBuses
; scsiBus
++) {
6231 // Get the SCSI bus scan data for this bus.
6234 lunInfo
= (PVOID
) (inquiryBuffer
+ adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
);
6238 if (lunInfo
->PathId
== PathId
&& lunInfo
->TargetId
== TargetId
) {
6240 inquiryData
= (PVOID
) lunInfo
->InquiryData
;
6242 if (RtlCompareMemory(inquiryData
->VendorId
, "TORiSAN CD-ROM CDR-C", 20) == 20) {
6243 ExFreePool(inquiryBuffer
);
6247 ExFreePool(inquiryBuffer
);
6251 if (!lunInfo
->NextInquiryDataOffset
) {
6255 lunInfo
= (PVOID
) (inquiryBuffer
+ lunInfo
->NextInquiryDataOffset
);
6259 ExFreePool(inquiryBuffer
);
6265 IsThisAnAtapiChanger(
6266 IN PDEVICE_OBJECT DeviceObject
,
6267 OUT PULONG DiscsPresent
6272 Routine Description:
6274 This routine is called by DriverEntry to determine whether an Atapi
6275 changer device is present.
6279 DeviceObject - Supplies the device object for the 'real' device.
6281 DiscsPresent - Supplies a pointer to the number of Discs supported by the changer.
6285 TRUE - if an Atapi changer device is found.
6290 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
6291 PMECHANICAL_STATUS_INFORMATION_HEADER mechanicalStatusBuffer
;
6293 SCSI_REQUEST_BLOCK srb
;
6294 PCDB cdb
= (PCDB
) &srb
.Cdb
[0];
6295 BOOLEAN retVal
= FALSE
;
6300 // Some devices can't handle 12 byte CDB's gracefully
6303 if(deviceExtension
->DeviceFlags
& DEV_NO_12BYTE_CDB
) {
6310 // Build and issue the mechanical status command.
6313 mechanicalStatusBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
6314 sizeof(MECHANICAL_STATUS_INFORMATION_HEADER
));
6316 if (!mechanicalStatusBuffer
) {
6321 // Build and send the Mechanism status CDB.
6324 RtlZeroMemory(&srb
, sizeof(srb
));
6327 srb
.TimeOutValue
= 20;
6329 cdb
->MECH_STATUS
.OperationCode
= SCSIOP_MECHANISM_STATUS
;
6330 cdb
->MECH_STATUS
.AllocationLength
[1] = sizeof(MECHANICAL_STATUS_INFORMATION_HEADER
);
6332 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
6334 mechanicalStatusBuffer
,
6335 sizeof(MECHANICAL_STATUS_INFORMATION_HEADER
),
6339 if (status
== STATUS_SUCCESS
) {
6342 // Indicate number of slots available
6345 *DiscsPresent
= mechanicalStatusBuffer
->NumberAvailableSlots
;
6346 if (*DiscsPresent
> 1) {
6351 // If only one disc, no need for this driver.
6359 // Device doesn't support this command.
6365 ExFreePool(mechanicalStatusBuffer
);
6373 IsThisAMultiLunDevice(
6374 IN PDEVICE_OBJECT DeviceObject
,
6375 IN PDEVICE_OBJECT PortDeviceObject
6379 Routine Description:
6381 This routine is called to determine whether a multi-lun
6386 DeviceObject - Supplies the device object for the 'real' device.
6390 TRUE - if a Multi-lun device is found.
6395 PSCSI_INQUIRY_DATA lunInfo
;
6396 PSCSI_ADAPTER_BUS_INFO adapterInfo
;
6397 PDEVICE_EXTENSION deviceExtension
= (PDEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
6398 PINQUIRYDATA inquiryData
;
6403 status
= ScsiClassGetInquiryData(PortDeviceObject
, (PSCSI_ADAPTER_BUS_INFO
*) &buffer
);
6405 if (!NT_SUCCESS(status
)) {
6406 DebugPrint((1,"IsThisAMultiLunDevice: ScsiClassGetInquiryData failed\n"));
6410 adapterInfo
= (PVOID
) buffer
;
6413 // For each SCSI bus this adapter supports ...
6416 for (scsiBus
=0; scsiBus
< adapterInfo
->NumberOfBuses
; scsiBus
++) {
6419 // Get the SCSI bus scan data for this bus.
6422 lunInfo
= (PVOID
) (buffer
+ adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
);
6424 while (adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
) {
6426 inquiryData
= (PVOID
)lunInfo
->InquiryData
;
6428 if ((lunInfo
->PathId
== deviceExtension
->PathId
) &&
6429 (lunInfo
->TargetId
== deviceExtension
->TargetId
) &&
6430 (inquiryData
->DeviceType
== READ_ONLY_DIRECT_ACCESS_DEVICE
)) {
6432 DebugPrint((1,"IsThisAMultiLunDevice: Vendor string is %.24s\n",
6433 inquiryData
->VendorId
));
6436 // If this device has more than one cdrom-type lun then we
6437 // won't support autoplay on it
6447 // Get next LunInfo.
6450 if (lunInfo
->NextInquiryDataOffset
== 0) {
6454 lunInfo
= (PVOID
) (buffer
+ lunInfo
->NextInquiryDataOffset
);
6463 IO_COMPLETION_ROUTINE CdRomUpdateGeometryCompletion
;
6466 CdRomUpdateGeometryCompletion(
6467 PDEVICE_OBJECT DeviceObject
,
6474 Routine Description:
6476 This routine andles the completion of the test unit ready irps
6477 used to determine if the media has changed. If the media has
6478 changed, this code signals the named event to wake up other
6479 system services that react to media change (aka AutoPlay).
6483 DeviceObject - the object for the completion
6484 Irp - the IRP being completed
6485 Context - the SRB from the IRP
6494 PSCSI_REQUEST_BLOCK srb
= (PSCSI_REQUEST_BLOCK
) Context
;
6495 PREAD_CAPACITY_DATA readCapacityBuffer
;
6496 PDEVICE_EXTENSION deviceExtension
;
6497 PIO_STACK_LOCATION irpStack
;
6506 // Get items saved in the private IRP stack location.
6509 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
6510 retryCount
= (ULONG
) irpStack
->Parameters
.Others
.Argument1
;
6511 originalIrp
= (PIRP
) irpStack
->Parameters
.Others
.Argument2
;
6513 if (!DeviceObject
) {
6514 DeviceObject
= irpStack
->DeviceObject
;
6516 ASSERT(DeviceObject
);
6518 deviceExtension
= DeviceObject
->DeviceExtension
;
6519 cddata
= (PCDROM_DATA
) (deviceExtension
+ 1);
6520 readCapacityBuffer
= srb
->DataBuffer
;
6522 if ((NT_SUCCESS(Irp
->IoStatus
.Status
)) && (SRB_STATUS(srb
->SrbStatus
) == SRB_STATUS_SUCCESS
)) {
6526 DebugPrint((2, "CdRomUpdateCapacityCompletion: [%lx] successful completion of buddy-irp %lx\n", originalIrp
, Irp
));
6528 // Copy sector size from read capacity buffer to device extension
6529 // in reverse byte order.
6532 from
= (PFOUR_BYTE
) &readCapacityBuffer
->BytesPerBlock
;
6533 to
= (PFOUR_BYTE
) &deviceExtension
->DiskGeometry
->BytesPerSector
;
6534 to
->Byte0
= from
->Byte3
;
6535 to
->Byte1
= from
->Byte2
;
6536 to
->Byte2
= from
->Byte1
;
6537 to
->Byte3
= from
->Byte0
;
6540 // Using the new BytesPerBlock, calculate and store the SectorShift.
6543 WHICH_BIT(deviceExtension
->DiskGeometry
->BytesPerSector
, deviceExtension
->SectorShift
);
6546 // Copy last sector in reverse byte order.
6549 from
= (PFOUR_BYTE
) &readCapacityBuffer
->LogicalBlockAddress
;
6550 to
= (PFOUR_BYTE
) &lastSector
;
6551 to
->Byte0
= from
->Byte3
;
6552 to
->Byte1
= from
->Byte2
;
6553 to
->Byte2
= from
->Byte1
;
6554 to
->Byte3
= from
->Byte0
;
6555 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(lastSector
+ 1);
6558 // Calculate number of cylinders.
6561 deviceExtension
->DiskGeometry
->Cylinders
.QuadPart
= (LONGLONG
)((lastSector
+ 1)/(32 * 64));
6562 deviceExtension
->PartitionLength
.QuadPart
=
6563 (deviceExtension
->PartitionLength
.QuadPart
<< deviceExtension
->SectorShift
);
6564 deviceExtension
->DiskGeometry
->MediaType
= RemovableMedia
;
6567 // Assume sectors per track are 32;
6570 deviceExtension
->DiskGeometry
->SectorsPerTrack
= 32;
6573 // Assume tracks per cylinder (number of heads) is 64.
6576 deviceExtension
->DiskGeometry
->TracksPerCylinder
= 64;
6580 DebugPrint((1, "CdRomUpdateCapacityCompletion: [%lx] unsuccessful completion of buddy-irp %lx (status - %lx)\n", originalIrp
, Irp
, Irp
->IoStatus
.Status
));
6582 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
6583 ScsiClassReleaseQueue(DeviceObject
);
6586 retry
= ScsiClassInterpretSenseInfo(DeviceObject
,
6597 DebugPrint((1, "CdRomUpdateCapacityCompletion: [%lx] Retrying request %lx .. thread is %lx\n", originalIrp
, Irp
, Irp
->Tail
.Overlay
.Thread
));
6599 // set up a one shot timer to get this process started over
6602 irpStack
->Parameters
.Others
.Argument1
= (PVOID
) retryCount
;
6603 irpStack
->Parameters
.Others
.Argument2
= (PVOID
) originalIrp
;
6604 irpStack
->Parameters
.Others
.Argument3
= (PVOID
) 2;
6607 // Setup the IRP to be submitted again in the timer routine.
6610 irpStack
= IoGetNextIrpStackLocation(Irp
);
6611 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
6612 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
6613 irpStack
->Parameters
.Scsi
.Srb
= srb
;
6614 IoSetCompletionRoutine(Irp
,
6615 CdRomUpdateGeometryCompletion
,
6622 // Set up the SRB for read capacity.
6625 srb
->CdbLength
= 10;
6626 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
6627 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
6629 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
6630 srb
->PathId
= deviceExtension
->PathId
;
6631 srb
->TargetId
= deviceExtension
->TargetId
;
6632 srb
->Lun
= deviceExtension
->Lun
;
6633 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
6634 srb
->SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
6635 srb
->DataTransferLength
= sizeof(READ_CAPACITY_DATA
);
6641 cdb
= (PCDB
) &srb
->Cdb
[0];
6642 cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
6643 cdb
->CDB10
.LogicalUnitNumber
= deviceExtension
->Lun
;
6646 // Requests queued onto this list will be sent to the
6647 // lower level driver during CdRomTickHandler
6650 ExInterlockedInsertHeadList(&cddata
->TimerIrpList
,
6651 &Irp
->Tail
.Overlay
.ListEntry
,
6652 &cddata
->TimerIrpSpinLock
);
6654 return STATUS_MORE_PROCESSING_REQUIRED
;
6658 // This has been bounced for a number of times. Error the
6659 // original request.
6662 originalIrp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
6663 RtlZeroMemory(deviceExtension
->DiskGeometry
, sizeof(DISK_GEOMETRY
));
6664 deviceExtension
->DiskGeometry
->BytesPerSector
= 2048;
6665 deviceExtension
->SectorShift
= 11;
6666 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(0x7fffffff);
6667 deviceExtension
->DiskGeometry
->MediaType
= RemovableMedia
;
6672 // Set up reasonable defaults
6675 RtlZeroMemory(deviceExtension
->DiskGeometry
, sizeof(DISK_GEOMETRY
));
6676 deviceExtension
->DiskGeometry
->BytesPerSector
= 2048;
6677 deviceExtension
->SectorShift
= 11;
6678 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(0x7fffffff);
6679 deviceExtension
->DiskGeometry
->MediaType
= RemovableMedia
;
6684 // Free resources held.
6687 ExFreePool(srb
->SenseInfoBuffer
);
6688 ExFreePool(srb
->DataBuffer
);
6690 if (Irp
->MdlAddress
) {
6691 IoFreeMdl(Irp
->MdlAddress
);
6694 if (originalIrp
->Tail
.Overlay
.Thread
) {
6696 DebugPrint((2, "CdRomUpdateCapacityCompletion: [%lx] completing original IRP\n", originalIrp
));
6697 IoCompleteRequest(originalIrp
, IO_DISK_INCREMENT
);
6700 DebugPrint((1, "CdRomUpdateCapacityCompletion: [%lx] original irp has "
6707 // It's now safe to either start the next request or let the waiting ioctl
6708 // request continue along it's merry way
6711 IoStartNextPacket(DeviceObject
, FALSE
);
6713 return STATUS_MORE_PROCESSING_REQUIRED
;
6718 CdRomUpdateCapacity(
6719 IN PDEVICE_EXTENSION DeviceExtension
,
6720 IN PIRP IrpToComplete
,
6721 IN OPTIONAL PKEVENT IoctlEvent
6726 Routine Description:
6728 This routine updates the capacity of the disk as recorded in the device extension.
6729 It also completes the IRP given with STATUS_VERIFY_REQUIRED. This routine is called
6730 when a media change has occurred and it is necessary to determine the capacity of the
6731 new media prior to the next access.
6735 DeviceExtension - the device to update
6736 IrpToComplete - the request that needs to be completed when done.
6747 PSCSI_REQUEST_BLOCK srb
;
6748 PREAD_CAPACITY_DATA capacityBuffer
;
6749 PIO_STACK_LOCATION irpStack
;
6753 irp
= IoAllocateIrp((CCHAR
)(DeviceExtension
->DeviceObject
->StackSize
+1),
6758 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
6760 capacityBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
6761 sizeof(READ_CAPACITY_DATA
));
6763 if (capacityBuffer
) {
6766 senseBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
6770 irp
->MdlAddress
= IoAllocateMdl(capacityBuffer
,
6771 sizeof(READ_CAPACITY_DATA
),
6776 if (irp
->MdlAddress
) {
6779 // Have all resources. Set up the IRP to send for the capacity.
6782 IoSetNextIrpStackLocation(irp
);
6783 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
6784 irp
->IoStatus
.Information
= 0;
6786 irp
->UserBuffer
= NULL
;
6789 // Save the device object and retry count in a private stack location.
6792 irpStack
= IoGetCurrentIrpStackLocation(irp
);
6793 irpStack
->DeviceObject
= DeviceExtension
->DeviceObject
;
6794 irpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
6795 irpStack
->Parameters
.Others
.Argument2
= (PVOID
) IrpToComplete
;
6798 // Construct the IRP stack for the lower level driver.
6801 irpStack
= IoGetNextIrpStackLocation(irp
);
6802 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
6803 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
6804 irpStack
->Parameters
.Scsi
.Srb
= srb
;
6805 IoSetCompletionRoutine(irp
,
6806 CdRomUpdateGeometryCompletion
,
6815 MmBuildMdlForNonPagedPool(irp
->MdlAddress
);
6819 // Set up the SRB for read capacity.
6822 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
6823 RtlZeroMemory(senseBuffer
, SENSE_BUFFER_SIZE
);
6824 srb
->CdbLength
= 10;
6825 srb
->TimeOutValue
= DeviceExtension
->TimeOutValue
;
6826 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
6828 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
6829 srb
->PathId
= DeviceExtension
->PathId
;
6830 srb
->TargetId
= DeviceExtension
->TargetId
;
6831 srb
->Lun
= DeviceExtension
->Lun
;
6832 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
6833 srb
->SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
6834 srb
->DataBuffer
= capacityBuffer
;
6835 srb
->DataTransferLength
= sizeof(READ_CAPACITY_DATA
);
6836 srb
->OriginalRequest
= irp
;
6837 srb
->SenseInfoBuffer
= senseBuffer
;
6838 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
6844 cdb
= (PCDB
) &srb
->Cdb
[0];
6845 cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
6846 cdb
->CDB10
.LogicalUnitNumber
= DeviceExtension
->Lun
;
6849 // Set the return value in the IRP that will be completed
6850 // upon completion of the read capacity.
6853 IrpToComplete
->IoStatus
.Status
= STATUS_VERIFY_REQUIRED
;
6854 IoMarkIrpPending(IrpToComplete
);
6856 status
= IoCallDriver(DeviceExtension
->PortDeviceObject
, irp
);
6859 // status is not checked because the completion routine for this
6860 // IRP will always get called and it will free the resources.
6863 return STATUS_PENDING
;
6866 ExFreePool(senseBuffer
);
6867 ExFreePool(capacityBuffer
);
6872 ExFreePool(capacityBuffer
);
6885 return STATUS_INSUFFICIENT_RESOURCES
;
6890 CdRomClassIoctlCompletion(
6891 IN PDEVICE_OBJECT DeviceObject
,
6898 Routine Description:
6900 This routine signals the event used by CdRomDeviceControl to synchronize
6901 class driver (and lower level driver) ioctls with cdrom's startio routine.
6902 The irp completion is short-circuited so that CdRomDeviceControl can
6903 reissue it once it wakes up.
6907 DeviceObject - the device object
6908 Irp - the request we are synchronizing
6909 Context - a PKEVENT that we need to signal
6918 PKEVENT syncEvent
= (PKEVENT
) Context
;
6920 DebugPrint((2, "CdRomClassIoctlCompletion: setting event for irp %#08lx\n",
6924 KeSetEvent(syncEvent
, IO_DISK_INCREMENT
, FALSE
);
6926 return STATUS_MORE_PROCESSING_REQUIRED
;