/*
- * ReactOS kernel
- * Copyright (C) 2001, 2002 ReactOS Team
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-/*
- * COPYRIGHT: See COPYING in the top level directory
- * PROJECT: ReactOS kernel
- * FILE: services/storage/cdrom/cdrom.c
- * PURPOSE: cdrom class driver
- * PROGRAMMER: Eric Kohl (ekohl@rz-online.de)
+ * PROJECT: ReactOS Storage Stack
+ * LICENSE: DDK - see license.txt in the root dir
+ * FILE: drivers/storage/cdrom/cdrom.c
+ * PURPOSE: CDROM driver
+ * PROGRAMMERS: Based on a source code sample from Microsoft NT4 DDK
*/
-/*
- * TODO:
- * - Add io timer routine for autorun support.
- * - Add cdaudio support (cd player).
- */
+#include <ntddk.h>
+#include <scsi.h>
+#include <ntddscsi.h>
+#include <ntdddisk.h>
+#include <ntddcdrm.h>
+#include <include/class2.h>
+#include <stdio.h>
+
+//#define NDEBUG
+#include <debug.h>
+
+#define CDB12GENERIC_LENGTH 12
+
+typedef struct _XA_CONTEXT {
+
+ //
+ // Pointer to the device object.
+ //
+
+ PDEVICE_OBJECT DeviceObject;
+
+ //
+ // Pointer to the original request when
+ // a mode select must be sent.
+ //
+
+ PIRP OriginalRequest;
+
+ //
+ // Pointer to the mode select srb.
+ //
+
+ PSCSI_REQUEST_BLOCK Srb;
+} XA_CONTEXT, *PXA_CONTEXT;
+
+typedef struct _ERROR_RECOVERY_DATA {
+ MODE_PARAMETER_HEADER Header;
+ MODE_PARAMETER_BLOCK BlockDescriptor;
+ MODE_READ_RECOVERY_PAGE ReadRecoveryPage;
+} ERROR_RECOVERY_DATA, *PERROR_RECOVERY_DATA;
+
+typedef struct _ERROR_RECOVERY_DATA10 {
+ MODE_PARAMETER_HEADER10 Header10;
+ MODE_PARAMETER_BLOCK BlockDescriptor10;
+ MODE_READ_RECOVERY_PAGE ReadRecoveryPage10;
+} ERROR_RECOVERY_DATA10, *PERROR_RECOVERY_DATA10;
+
+//
+// CdRom specific addition to device extension.
+//
+
+typedef struct _CDROM_DATA {
+
+ //
+ // Indicates whether an audio play operation
+ // is currently being performed.
+ //
+
+ BOOLEAN PlayActive;
+
+ //
+ // Indicates whether the blocksize used for user data
+ // is 2048 or 2352.
+ //
+
+ BOOLEAN RawAccess;
+
+ //
+ // Indicates whether 6 or 10 byte mode sense/select
+ // should be used.
+ //
+
+ USHORT XAFlags;
+
+ //
+ // Storage for the error recovery page. This is used
+ // as an easy method to switch block sizes.
+ //
+
+ union {
+ ERROR_RECOVERY_DATA u1;
+ ERROR_RECOVERY_DATA10 u2;
+ };
+
+
+ //
+ // Pointer to the original irp for the raw read.
+ //
+
+ PIRP SavedReadIrp;
+
+ //
+ // Used to protect accesses to the RawAccess flag.
+ //
+
+ KSPIN_LOCK FormSpinLock;
+
+ //
+ // Even if media change support is requested, there are some devices
+ // that are not supported. This flag will indicate that such a device
+ // is present when it is FALSE.
+ //
+
+ BOOLEAN MediaChangeSupported;
+
+ //
+ // The media change event is being supported. The media change timer
+ // should be running whenever this is true.
+ //
+
+ BOOLEAN MediaChange;
+
+ //
+ // The timer value to support media change events. This is a countdown
+ // value used to determine when to poll the device for a media change.
+ // The max value for the timer is 255 seconds.
+ //
+
+ UCHAR MediaChangeCountDown;
+
+#ifdef DBG
+ //
+ // Second timer to keep track of how long the media change IRP has been
+ // in use. If this value exceeds the timeout (#defined) then we should
+ // print out a message to the user and set the MediaChangeIrpLost flag
+ //
+
+ SHORT MediaChangeIrpTimeInUse;
+
+ //
+ // Set by CdRomTickHandler when we determine that the media change irp has
+ // been lost
+ //
+
+ BOOLEAN MediaChangeIrpLost;
+#endif
+
+ UCHAR PadReserve; // use this for new flags.
+
+ //
+ // An IRP is allocated and kept for the duration that media change
+ // detection is in effect. If this is NULL and MediaChange is TRUE,
+ // the detection is in progress. This should always be NULL when
+ // MediaChange is FALSE.
+ //
+
+ PIRP MediaChangeIrp;
+
+ //
+ // The timer work list is a collection of IRPS that are prepared for
+ // submission, but need to allow some time to pass before they are
+ // run.
+ //
+
+ LIST_ENTRY TimerIrpList;
+ KSPIN_LOCK TimerIrpSpinLock;
+
+} CDROM_DATA, *PCDROM_DATA;
+
+#define DEVICE_EXTENSION_SIZE sizeof(DEVICE_EXTENSION) + sizeof(CDROM_DATA)
+#define SCSI_CDROM_TIMEOUT 10
+#define SCSI_CHANGER_BONUS_TIMEOUT 10
+#define HITACHI_MODE_DATA_SIZE 12
+#define MODE_DATA_SIZE 64
+#define RAW_SECTOR_SIZE 2352
+#define COOKED_SECTOR_SIZE 2048
+#define MEDIA_CHANGE_DEFAULT_TIME 4
+#define CDROM_SRB_LIST_SIZE 4
+
+
+#ifdef DBG
+
+//
+// Used to detect the loss of the autorun irp. The driver prints out a message
+// (debug level 0) if this timeout ever occurs
+//
+#define MEDIA_CHANGE_TIMEOUT_TIME 300
+
+#endif
+
+#define PLAY_ACTIVE(DeviceExtension) (((PCDROM_DATA)(DeviceExtension + 1))->PlayActive)
+
+#define MSF_TO_LBA(Minutes,Seconds,Frames) \
+ (ULONG)((60 * 75 * (Minutes)) + (75 * (Seconds)) + ((Frames) - 150))
+
+#define LBA_TO_MSF(Lba,Minutes,Seconds,Frames) \
+{ \
+ (Minutes) = (UCHAR)(Lba / (60 * 75)); \
+ (Seconds) = (UCHAR)((Lba % (60 * 75)) / 75); \
+ (Frames) = (UCHAR)((Lba % (60 * 75)) % 75); \
+}
+
+#define DEC_TO_BCD(x) (((x / 10) << 4) + (x % 10))
+
+//
+// Define flags for XA, CDDA, and Mode Select/Sense
+//
+
+#define XA_USE_6_BYTE 0x01
+#define XA_USE_10_BYTE 0x02
+#define XA_USE_READ_CD 0x04
+#define XA_NOT_SUPPORTED 0x08
+
+#define PLEXTOR_CDDA 0x10
+#define NEC_CDDA 0x20
+
+//
+// Sector types for READ_CD
+//
+
+#define ANY_SECTOR 0
+#define CD_DA_SECTOR 1
+#define YELLOW_MODE1_SECTOR 2
+#define YELLOW_MODE2_SECTOR 3
+#define FORM2_MODE1_SECTOR 4
+#define FORM2_MODE2_SECTOR 5
+
+
+#ifdef POOL_TAGGING
+#ifdef ExAllocatePool
+#undef ExAllocatePool
+#endif
+#define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'CscS')
+#endif
+
+\f
+NTSTATUS
+STDCALL
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+BOOLEAN
+STDCALL
+ScsiCdRomFindDevices(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath,
+ IN PCLASS_INIT_DATA InitializationData,
+ IN PDEVICE_OBJECT PortDeviceObject,
+ IN ULONG PortNumber
+ );
+
+NTSTATUS
+STDCALL
+ScsiCdRomOpenClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+STDCALL
+ScsiCdRomReadVerification(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+STDCALL
+ScsiCdRomSwitchMode(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN ULONG SectorSize,
+ IN PIRP OriginalRequest
+ );
+
+NTSTATUS
+STDCALL
+CdRomDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+STDCALL
+CdRomDeviceControlCompletion(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ );
+
+NTSTATUS
+STDCALL
+CdRomSetVolumeIntermediateCompletion(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ );
+
+NTSTATUS
+STDCALL
+CdRomSwitchModeCompletion(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ );
+
+NTSTATUS
+STDCALL
+CdRomXACompletion(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ );
+
+NTSTATUS
+STDCALL
+CdRomClassIoctlCompletion(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ );
+
+VOID
+STDCALL
+ScsiCdRomStartIo(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+STDCALL
+CdRomTickHandler(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PVOID Context
+ );
+
+BOOLEAN
+STDCALL
+CdRomCheckRegistryForMediaChangeValue(
+ IN PUNICODE_STRING RegistryPath,
+ IN ULONG DeviceNumber
+ );
+
+NTSTATUS
+STDCALL
+CdRomUpdateCapacity(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PIRP IrpToComplete,
+ IN OPTIONAL PKEVENT IoctlEvent
+ );
+
+NTSTATUS
+STDCALL
+CreateCdRomDeviceObject(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PDEVICE_OBJECT PortDeviceObject,
+ IN ULONG PortNumber,
+ IN PULONG DeviceCount,
+ PIO_SCSI_CAPABILITIES PortCapabilities,
+ IN PSCSI_INQUIRY_DATA LunInfo,
+ IN PCLASS_INIT_DATA InitializationData,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+VOID
+STDCALL
+ScanForSpecial(
+ PDEVICE_OBJECT DeviceObject,
+ PINQUIRYDATA InquiryData,
+ PIO_SCSI_CAPABILITIES PortCapabilities
+ );
+
+BOOLEAN
+STDCALL
+CdRomIsPlayActive(
+ IN PDEVICE_OBJECT DeviceObject
+ );
+
+VOID
+STDCALL
+HitachProcessError(
+ PDEVICE_OBJECT DeviceObject,
+ PSCSI_REQUEST_BLOCK Srb,
+ NTSTATUS *Status,
+ BOOLEAN *Retry
+ );
+
+VOID
+STDCALL
+ToshibaProcessError(
+ PDEVICE_OBJECT DeviceObject,
+ PSCSI_REQUEST_BLOCK Srb,
+ NTSTATUS *Status,
+ BOOLEAN *Retry
+ );
+
+BOOLEAN
+STDCALL
+IsThisAnAtapiChanger(
+ IN PDEVICE_OBJECT DeviceObject,
+ OUT PULONG DiscsPresent
+ );
+
+BOOLEAN
+STDCALL
+IsThisASanyo(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN UCHAR PathId,
+ IN UCHAR TargetId
+ );
+
+BOOLEAN
+STDCALL
+IsThisAMultiLunDevice(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PDEVICE_OBJECT PortDeviceObject
+ );
+
+VOID
+STDCALL
+CdRomCreateNamedEvent(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN ULONG DeviceNumber
+ );
+
+#ifdef _PPC_
+NTSTATUS
+FindScsiAdapter (
+ IN HANDLE KeyHandle,
+ IN UNICODE_STRING ScsiUnicodeString[],
+ OUT PUCHAR IntermediateController
+ );
+#endif
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, DriverEntry)
+#pragma alloc_text(PAGE, ScsiCdRomFindDevices)
+#pragma alloc_text(PAGE, CreateCdRomDeviceObject)
+#pragma alloc_text(PAGE, ScanForSpecial)
+//#pragma alloc_text(PAGE, CdRomDeviceControl)
+#pragma alloc_text(PAGE, HitachProcessError)
+#pragma alloc_text(PAGE, CdRomIsPlayActive)
+#pragma alloc_text(PAGE, ScsiCdRomReadVerification)
+#pragma alloc_text(INIT, CdRomCheckRegistryForMediaChangeValue)
+#pragma alloc_text(INIT, IsThisAnAtapiChanger)
+#pragma alloc_text(INIT, IsThisASanyo)
+#pragma alloc_text(INIT, IsThisAMultiLunDevice)
+#pragma alloc_text(INIT, CdRomCreateNamedEvent)
+#ifdef _PPC_
+#pragma alloc_text(PAGE, FindScsiAdapter)
+#endif
+#endif
+
+ULONG NoLoad = 0;
+
+\f
+NTSTATUS
+STDCALL
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the cdrom class driver.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by system.
+
+ RegistryPath - Pointer to the name of the services node for this driver.
+
+Return Value:
+
+ The function value is the final status from the initialization operation.
+
+--*/
+
+{
+ CLASS_INIT_DATA InitializationData;
+
+ if(NoLoad) {
+ return STATUS_NO_SUCH_DEVICE;
+ }
+
+ //
+ // Zero InitData
+ //
+
+ RtlZeroMemory (&InitializationData, sizeof(CLASS_INIT_DATA));
+
+ //
+ // Set sizes
+ //
+
+ InitializationData.InitializationDataSize = sizeof(CLASS_INIT_DATA);
+ InitializationData.DeviceExtensionSize = DEVICE_EXTENSION_SIZE;
+
+ InitializationData.DeviceType = FILE_DEVICE_CD_ROM;
+ InitializationData.DeviceCharacteristics = FILE_REMOVABLE_MEDIA | FILE_READ_ONLY_DEVICE;
+
+ //
+ // Set entry points
+ //
+
+ InitializationData.ClassReadWriteVerification = ScsiCdRomReadVerification;
+ InitializationData.ClassDeviceControl = CdRomDeviceControl;
+ InitializationData.ClassFindDevices = ScsiCdRomFindDevices;
+ InitializationData.ClassShutdownFlush = NULL;
+ InitializationData.ClassCreateClose = NULL;
+ InitializationData.ClassStartIo = ScsiCdRomStartIo;
+
+ //
+ // Call the class init routine
+ //
+
+ return ScsiClassInitialize( DriverObject, RegistryPath, &InitializationData);
+
+} // end DriverEntry()
+
+\f
+BOOLEAN
+STDCALL
+ScsiCdRomFindDevices(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath,
+ IN PCLASS_INIT_DATA InitializationData,
+ IN PDEVICE_OBJECT PortDeviceObject,
+ IN ULONG PortNumber
+ )
+
+/*++
+
+Routine Description:
+
+ Connect to SCSI port driver. Get adapter capabilities and
+ SCSI bus configuration information. Search inquiry data
+ for CDROM devices to process.
+
+Arguments:
+
+ DriverObject - CDROM class driver object.
+ PortDeviceObject - SCSI port driver device object.
+ PortNumber - The system ordinal for this scsi adapter.
+
+Return Value:
+
+ TRUE if CDROM device present on this SCSI adapter.
+
+--*/
+
+{
+ PIO_SCSI_CAPABILITIES portCapabilities;
+ PULONG cdRomCount;
+ PCHAR buffer;
+ PSCSI_INQUIRY_DATA lunInfo;
+ PSCSI_ADAPTER_BUS_INFO adapterInfo;
+ PINQUIRYDATA inquiryData;
+ ULONG scsiBus;
+ NTSTATUS status;
+ BOOLEAN foundDevice = FALSE;
+
+ //
+ // Call port driver to get adapter capabilities.
+ //
+
+ status = ScsiClassGetCapabilities(PortDeviceObject, &portCapabilities);
+
+ if (!NT_SUCCESS(status)) {
+ DebugPrint((1,"FindScsiDevices: ScsiClassGetCapabilities failed\n"));
+ return foundDevice;
+ }
+
+ //
+ // Call port driver to get inquiry information to find cdroms.
+ //
+
+ status = ScsiClassGetInquiryData(PortDeviceObject, (PSCSI_ADAPTER_BUS_INFO *) &buffer);
+
+ if (!NT_SUCCESS(status)) {
+ DebugPrint((1,"FindScsiDevices: ScsiClassGetInquiryData failed\n"));
+ return foundDevice;
+ }
+
+ //
+ // Get the address of the count of the number of cdroms already initialized.
+ //
+
+ cdRomCount = &IoGetConfigurationInformation()->CdRomCount;
+ adapterInfo = (PVOID) buffer;
+
+ //
+ // For each SCSI bus this adapter supports ...
+ //
+
+ for (scsiBus=0; scsiBus < adapterInfo->NumberOfBuses; scsiBus++) {
+
+ //
+ // Get the SCSI bus scan data for this bus.
+ //
+
+ lunInfo = (PVOID) (buffer + adapterInfo->BusData[scsiBus].InquiryDataOffset);
+
+ //
+ // Search list for unclaimed disk devices.
+ //
+
+ while (adapterInfo->BusData[scsiBus].InquiryDataOffset) {
+
+ inquiryData = (PVOID)lunInfo->InquiryData;
+
+ if ((inquiryData->DeviceType == READ_ONLY_DIRECT_ACCESS_DEVICE) &&
+ (inquiryData->DeviceTypeQualifier == 0) &&
+ (!lunInfo->DeviceClaimed)) {
+
+ DebugPrint((1,"FindScsiDevices: Vendor string is %.24s\n",
+ inquiryData->VendorId));
+
+ //
+ // Create device objects for cdrom
+ //
+
+ status = CreateCdRomDeviceObject(DriverObject,
+ PortDeviceObject,
+ PortNumber,
+ cdRomCount,
+ portCapabilities,
+ lunInfo,
+ InitializationData,
+ RegistryPath);
+
+ if (NT_SUCCESS(status)) {
+
+ //
+ // Increment system cdrom device count.
+ //
+
+ (*cdRomCount)++;
+
+ //
+ // Indicate that a cdrom device was found.
+ //
+
+ foundDevice = TRUE;
+ }
+ }
+
+ //
+ // Get next LunInfo.
+ //
+
+ if (lunInfo->NextInquiryDataOffset == 0) {
+ break;
+ }
+
+ lunInfo = (PVOID) (buffer + lunInfo->NextInquiryDataOffset);
+ }
+ }
+
+ ExFreePool(buffer);
+
+
+ return foundDevice;
+
+} // end FindScsiCdRoms()
+
+\f
+VOID
+STDCALL
+CdRomCreateNamedEvent(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN ULONG DeviceNumber
+ )
+
+/*++
+
+Routine Description:
+
+ Create the named synchronization event for notification of media change
+ events to the system. The event is reset before this function returns.
+
+Arguments:
+
+ DeviceExtension - the device extension pointer for storage of the event pointer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UNICODE_STRING unicodeString;
+ OBJECT_ATTRIBUTES objectAttributes;
+ CCHAR eventNameBuffer[MAXIMUM_FILENAME_LENGTH];
+ STRING eventNameString;
+ HANDLE handle;
+ NTSTATUS status;
+
+
+ sprintf(eventNameBuffer,"\\Device\\MediaChangeEvent%d",
+ DeviceNumber);
+
+ RtlInitString(&eventNameString,
+ eventNameBuffer);
+
+ status = RtlAnsiStringToUnicodeString(&unicodeString,
+ &eventNameString,
+ TRUE);
+
+ if (!NT_SUCCESS(status)) {
+ return;
+ }
+
+ InitializeObjectAttributes(&objectAttributes,
+ &unicodeString,
+ OBJ_PERMANENT | OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
+ NULL,
+ NULL);
+
+ DeviceExtension->MediaChangeEvent = IoCreateSynchronizationEvent(&unicodeString,
+ &handle);
+ DeviceExtension->MediaChangeEventHandle = handle;
+
+ KeClearEvent(DeviceExtension->MediaChangeEvent);
+
+ RtlFreeUnicodeString(&unicodeString);
+}
+
+\f
+NTSTATUS
+STDCALL
+CreateCdRomDeviceObject(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PDEVICE_OBJECT PortDeviceObject,
+ IN ULONG PortNumber,
+ IN PULONG DeviceCount,
+ IN PIO_SCSI_CAPABILITIES PortCapabilities,
+ IN PSCSI_INQUIRY_DATA LunInfo,
+ IN PCLASS_INIT_DATA InitializationData,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates an object for the device and then calls the
+ SCSI port driver for media capacity and sector size.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by system.
+ PortDeviceObject - to connect to SCSI port driver.
+ DeviceCount - Number of previously installed CDROMs.
+ PortCapabilities - Pointer to structure returned by SCSI port
+ driver describing adapter capabilites (and limitations).
+ LunInfo - Pointer to configuration information for this device.
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+{
+ UCHAR ntNameBuffer[64];
+ STRING ntNameString;
+ UNICODE_STRING ntUnicodeString;
+ NTSTATUS status;
+ BOOLEAN changerDevice;
+ SCSI_REQUEST_BLOCK srb;
+ ULONG length;
+ PCDROM_DATA cddata;
+ PCDB cdb;
+ PVOID senseData = NULL;
+ PDEVICE_OBJECT deviceObject = NULL;
+ PDEVICE_EXTENSION deviceExtension = NULL;
+ PUCHAR buffer;
+ ULONG bps;
+ ULONG lastBit;
+ ULONG timeOut;
+ BOOLEAN srbListInitialized = FALSE;
+
+ //
+ // Claim the device. Note that any errors after this
+ // will goto the generic handler, where the device will
+ // be released.
+ //
+
+ status = ScsiClassClaimDevice(PortDeviceObject,
+ LunInfo,
+ FALSE,
+ &PortDeviceObject);
+
+ if (!NT_SUCCESS(status)) {
+ return(status);
+ }
+
+ //
+ // Create device object for this device.
+ //
+
+ sprintf(ntNameBuffer,
+ "\\Device\\CdRom%d",
+ *DeviceCount);
+
+ status = ScsiClassCreateDeviceObject(DriverObject,
+ ntNameBuffer,
+ NULL,
+ &deviceObject,
+ InitializationData);
+
+ if (!NT_SUCCESS(status)) {
+ DebugPrint((1,"CreateCdRomDeviceObjects: Can not create device %s\n",
+ ntNameBuffer));
+
+ RtlFreeUnicodeString(&ntUnicodeString);
+ goto CreateCdRomDeviceObjectExit;
+ }
+
+ //
+ // Indicate that IRPs should include MDLs.
+ //
+
+ deviceObject->Flags |= DO_DIRECT_IO;
+
+ //
+ // Set up required stack size in device object.
+ //
+
+ deviceObject->StackSize = PortDeviceObject->StackSize + 2;
+
+ deviceExtension = deviceObject->DeviceExtension;
+
+ //
+ // Allocate spinlock for split request completion.
+ //
+
+ KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock);
+
+ //
+ // This is the physical device.
+ //
+
+ deviceExtension->PhysicalDevice = deviceObject;
+
+ //
+ // Initialize lock count to zero. The lock count is used to
+ // disable the ejection mechanism when media is mounted.
+ //
+
+ deviceExtension->LockCount = 0;
+
+ //
+ // Save system cdrom number
+ //
+
+ deviceExtension->DeviceNumber = *DeviceCount;
+
+ //
+ // Copy port device object to device extension.
+ //
+
+ deviceExtension->PortDeviceObject = PortDeviceObject;
+
+ //
+ // Set the alignment requirements for the device based on the
+ // host adapter requirements
+ //
+
+ if (PortDeviceObject->AlignmentRequirement > deviceObject->AlignmentRequirement) {
+ deviceObject->AlignmentRequirement = PortDeviceObject->AlignmentRequirement;
+ }
+
+ //
+ // Save address of port driver capabilities.
+ //
+
+ deviceExtension->PortCapabilities = PortCapabilities;
+
+ //
+ // Clear SRB flags.
+ //
+
+ deviceExtension->SrbFlags = 0;
+ deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
+
+ //
+ // Allocate request sense buffer.
+ //
+
+ senseData = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
+
+ if (senseData == NULL) {
+
+ //
+ // The buffer cannot be allocated.
+ //
+
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto CreateCdRomDeviceObjectExit;
+ }
+
+ //
+ // Set the sense data pointer in the device extension.
+ //
+
+ deviceExtension->SenseData = senseData;
+
+ //
+ // CDROMs are not partitionable so starting offset is 0.
+ //
+
+ deviceExtension->StartingOffset.LowPart = 0;
+ deviceExtension->StartingOffset.HighPart = 0;
+
+ //
+ // Path/TargetId/LUN describes a device location on the SCSI bus.
+ // This information comes from the LunInfo buffer.
+ //
+
+ deviceExtension->PortNumber = (UCHAR)PortNumber;
+ deviceExtension->PathId = LunInfo->PathId;
+ deviceExtension->TargetId = LunInfo->TargetId;
+ deviceExtension->Lun = LunInfo->Lun;
+
+ //
+ // Set timeout value in seconds.
+ //
+
+ timeOut = ScsiClassQueryTimeOutRegistryValue(RegistryPath);
+ if (timeOut) {
+ deviceExtension->TimeOutValue = timeOut;
+ } else {
+ deviceExtension->TimeOutValue = SCSI_CDROM_TIMEOUT;
+ }
+
+ //
+ // Build the lookaside list for srb's for the physical disk. Should only
+ // need a couple.
+ //
+
+ ScsiClassInitializeSrbLookasideList(deviceExtension,
+ CDROM_SRB_LIST_SIZE);
+
+ srbListInitialized = TRUE;
+
+ //
+ // Back pointer to device object.
+ //
+
+ deviceExtension->DeviceObject = deviceObject;
+
+ //
+ // Allocate buffer for drive geometry.
+ //
+
+ deviceExtension->DiskGeometry =
+ ExAllocatePool(NonPagedPool, sizeof(DISK_GEOMETRY));
+
+ if (deviceExtension->DiskGeometry == NULL) {
+
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto CreateCdRomDeviceObjectExit;
+ }
+
+ //
+ // Set up media change support defaults.
+ //
+
+ cddata = (PCDROM_DATA)(deviceExtension + 1);
+
+ KeInitializeSpinLock(&cddata->FormSpinLock);
+ KeInitializeSpinLock(&cddata->TimerIrpSpinLock);
+ InitializeListHead(&cddata->TimerIrpList);
+
+ cddata->MediaChangeCountDown = MEDIA_CHANGE_DEFAULT_TIME;
+ cddata->MediaChangeSupported = FALSE;
+ cddata->MediaChange = FALSE;
+
+ //
+ // Assume that there is initially no media in the device
+ // only notify upper layers if there is something there
+ //
+
+ deviceExtension->MediaChangeNoMedia = TRUE;
+ cddata->MediaChangeIrp = NULL;
+#ifdef DBG
+ cddata->MediaChangeIrpTimeInUse = 0;
+ cddata->MediaChangeIrpLost = FALSE;
+#endif
+
+ //
+ // Scan for Scsi controllers that require special processing.
+ //
+
+ ScanForSpecial(deviceObject,
+ (PINQUIRYDATA) LunInfo->InquiryData,
+ PortCapabilities);
+
+ //
+ // Do READ CAPACITY. This SCSI command
+ // returns the last sector address on the device
+ // and the bytes per sector.
+ // These are used to calculate the drive capacity
+ // in bytes.
+ //
+
+ status = ScsiClassReadDriveCapacity(deviceObject);
+ bps = deviceExtension->DiskGeometry->BytesPerSector;
+
+ if (!NT_SUCCESS(status) || !bps) {
+
+ DebugPrint((1,
+ "CreateCdRomDeviceObjects: Can't read capacity for device %s\n",
+ ntNameBuffer));
+
+ //
+ // Set disk geometry to default values (per ISO 9660).
+ //
+
+ bps = 2048;
+ deviceExtension->SectorShift = 11;
+ deviceExtension->PartitionLength.QuadPart = (LONGLONG)(0x7fffffff);
+ } else {
+
+ //
+ // Insure that bytes per sector is a power of 2
+ // This corrects a problem with the HP 4020i CDR where it
+ // returns an incorrect number for bytes per sector.
+ //
+
+ lastBit = (ULONG) -1;
+ while (bps) {
+ lastBit++;
+ bps = bps >> 1;
+ }
+
+ bps = 1 << lastBit;
+ }
+ deviceExtension->DiskGeometry->BytesPerSector = bps;
+ DebugPrint((2, "CreateCdRomDeviceObject: Calc'd bps = %x\n", bps));
+
+ //
+ // Check to see if this is some sort of changer device
+ //
+
+ changerDevice = FALSE;
+
+ //
+ // Search for devices that have special requirements for media
+ // change support.
+ //
+
+ if (deviceExtension->Lun > 0) {
+ changerDevice = TRUE;
+ }
+
+ if (!changerDevice) {
+ changerDevice = IsThisASanyo(deviceObject, deviceExtension->PathId,
+ deviceExtension->TargetId);
+ }
+
+ if (!changerDevice) {
+ ULONG tmp;
+ changerDevice = IsThisAnAtapiChanger(deviceObject, &tmp);
+ }
+
+ if (!changerDevice) {
+ changerDevice = IsThisAMultiLunDevice(deviceObject, PortDeviceObject);
+ }
+
+ //
+ // If it is a changer device, increment the timeout to take platter-swapping
+ // time into account
+ //
+
+ if(changerDevice) {
+ deviceExtension->TimeOutValue += SCSI_CHANGER_BONUS_TIMEOUT;
+ }
+
+ //
+ // Create the media change named event. If this succeeds then continue
+ // initializing the media change support data items.
+ //
+
+ CdRomCreateNamedEvent(deviceExtension,*DeviceCount);
+ if (deviceExtension->MediaChangeEvent) {
+
+ //
+ // If this is not a changer, get an IRP for the timer request
+ // and initialize the timer.
+ //
+
+ if (!changerDevice) {
+
+ //
+ // Not a changer device - continue with media change initialization.
+ // Determine if the user actually wants media change events.
+ //
+
+ if (CdRomCheckRegistryForMediaChangeValue(RegistryPath, *DeviceCount)) {
+ PIO_STACK_LOCATION irpStack;
+ PSCSI_REQUEST_BLOCK srb;
+ PIRP irp;
+
+ //
+ // User wants it - preallocate IRP and SRB.
+ //
+
+ irp = IoAllocateIrp((CCHAR)(deviceObject->StackSize+1),
+ FALSE);
+ if (irp) {
+ PVOID buffer;
+
+ srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
+ buffer = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
+
+ if (srb && buffer) {
+ PCDB cdb;
+
+ //
+ // All resources have been allocated set up the IRP.
+ //
+
+ IoSetNextIrpStackLocation(irp);
+ irpStack = IoGetCurrentIrpStackLocation(irp);
+ irpStack->DeviceObject = deviceObject;
+ irpStack = IoGetNextIrpStackLocation(irp);
+ cddata->MediaChangeIrp = irp;
+ irpStack->Parameters.Scsi.Srb = srb;
+
+ //
+ // Initialize the SRB
+ //
+
+ RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
+
+ srb->CdbLength = 6;
+ srb->TimeOutValue = deviceExtension->TimeOutValue * 2;
+ srb->QueueTag = SP_UNTAGGED;
+ srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
+ srb->Length = SCSI_REQUEST_BLOCK_SIZE;
+ srb->PathId = deviceExtension->PathId;
+ srb->TargetId = deviceExtension->TargetId;
+ srb->Lun = deviceExtension->Lun;
+ srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
+
+ //
+ // Initialize and set up the sense information buffer
+ //
+
+ RtlZeroMemory(buffer, SENSE_BUFFER_SIZE);
+ srb->SenseInfoBuffer = buffer;
+ srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
+
+ //
+ // Initialize the CDB
+ //
+
+ cdb = (PCDB)&srb->Cdb[0];
+ cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
+ cdb->CDB6GENERIC.LogicalUnitNumber = deviceExtension->Lun;
+
+ //
+ // It is ok to support media change events on this device.
+ //
+
+ cddata->MediaChangeSupported = TRUE;
+ cddata->MediaChange = TRUE;
+
+ } else {
+
+ if (srb) {
+ ExFreePool(srb);
+ }
+ if (buffer) {
+ ExFreePool(buffer);
+ }
+ IoFreeIrp(irp);
+ }
+ }
+ } else {
+ deviceExtension->MediaChangeEvent = NULL;
+ }
+ } else {
+ deviceExtension->MediaChangeEvent = NULL;
+ }
+ }
+
+ //
+ // Assume use of 6-byte mode sense/select for now.
+ //
+
+ cddata->XAFlags |= XA_USE_6_BYTE;
+
+ //
+ // Build and issue mode sense with Read error recovery page. This will be used to change
+ // block size in case of any raw reads (Mode 2, Form 2).
+ //
+
+ length = (sizeof(MODE_READ_RECOVERY_PAGE) + MODE_BLOCK_DESC_LENGTH + MODE_HEADER_LENGTH);
+
+ RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
+
+ srb.CdbLength = 6;
+ cdb = (PCDB)srb.Cdb;
+
+ //
+ // Set timeout value from device extension.
+ //
+
+ srb.TimeOutValue = deviceExtension->TimeOutValue;
+
+ //
+ // Build the MODE SENSE CDB. The data returned will be kept in the device extension
+ // and used to set block size.
+ //
+
+ cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
+ cdb->MODE_SENSE.PageCode = 0x1;
+ cdb->MODE_SENSE.AllocationLength = (UCHAR)length;
+
+ buffer = ExAllocatePool(NonPagedPoolCacheAligned, (sizeof(MODE_READ_RECOVERY_PAGE) + MODE_BLOCK_DESC_LENGTH + MODE_HEADER_LENGTH10));
+ if (!buffer) {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto CreateCdRomDeviceObjectExit;
+ }
+
+ status = ScsiClassSendSrbSynchronous(deviceObject,
+ &srb,
+ buffer,
+ length,
+ FALSE);
+ if (!NT_SUCCESS(status)) {
+
+ //
+ // May be Atapi, try 10-byte.
+ //
+
+ length = (sizeof(MODE_READ_RECOVERY_PAGE) + MODE_BLOCK_DESC_LENGTH + MODE_HEADER_LENGTH10);
+
+ RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
+
+ //
+ // Build the MODE SENSE CDB.
+ //
+
+ srb.CdbLength = 10;
+ cdb = (PCDB)srb.Cdb;
+
+ //
+ // Set timeout value from device extension.
+ //
+
+ srb.TimeOutValue = deviceExtension->TimeOutValue;
+
+ cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
+ cdb->MODE_SENSE10.PageCode = 0x1;
+
+ cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(length >> 8);
+ cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(length & 0xFF);
+
+ status = ScsiClassSendSrbSynchronous(deviceObject,
+ &srb,
+ buffer,
+ length,
+ FALSE);
+ if (status == STATUS_DATA_OVERRUN) {
+
+ //
+ // Build and issue the ReadCd command to ensure that this device supports it.
+ //
+
+ RtlZeroMemory(cdb, 12);
+
+ cdb->READ_CD.OperationCode = SCSIOP_READ_CD;
+
+ status = ScsiClassSendSrbSynchronous(deviceObject,
+ &srb,
+ NULL,
+ 0,
+ FALSE);
+
+ //
+ // If the command wasn't rejected then support the READ_CD.
+ //
+
+ if (NT_SUCCESS(status) || (status == STATUS_NO_MEDIA_IN_DEVICE)) {
+
+ //
+ // Using Read CD precludes issueing a mode select to
+ // set the user data size. So, no buffer copy is
+ // necessary.
+ //
+
+ cddata->XAFlags &= ~XA_USE_6_BYTE;
+ cddata->XAFlags = XA_USE_READ_CD | XA_USE_10_BYTE;
+ } else {
+
+ RtlCopyMemory(&cddata->u1.Header, buffer, sizeof(ERROR_RECOVERY_DATA10));
+ cddata->u1.Header.ModeDataLength = 0;
+
+ cddata->XAFlags &= ~XA_USE_6_BYTE;
+ cddata->XAFlags |= XA_USE_10_BYTE;
+ }
+
+ } else if (NT_SUCCESS(status)) {
+
+ RtlCopyMemory(&cddata->u1.Header, buffer, sizeof(ERROR_RECOVERY_DATA10));
+ cddata->u1.Header.ModeDataLength = 0;
+
+ cddata->XAFlags &= ~XA_USE_6_BYTE;
+ cddata->XAFlags |= XA_USE_10_BYTE;
+
+ } else {
+ cddata->XAFlags |= XA_NOT_SUPPORTED;
+ }
+ } else {
+ RtlCopyMemory(&cddata->u1.Header, buffer, sizeof(ERROR_RECOVERY_DATA));
+ cddata->u1.Header.ModeDataLength = 0;
+ }
+
+ ExFreePool(buffer);
+
+ //
+ // Start the timer now regardless of if Autorun is enabled.
+ // The timer must run forever since IoStopTimer faults.
+ //
+
+ IoInitializeTimer(deviceObject, CdRomTickHandler, NULL);
+ IoStartTimer(deviceObject);
+
+ return(STATUS_SUCCESS);
+
+CreateCdRomDeviceObjectExit:
+
+ //
+ // Release the device since an error occured.
+ //
+
+ ScsiClassClaimDevice(PortDeviceObject,
+ LunInfo,
+ TRUE,
+ NULL);
+
+ if (senseData != NULL) {
+ ExFreePool(senseData);
+ }
+
+ if (deviceExtension->DiskGeometry != NULL) {
+ ExFreePool(deviceExtension->DiskGeometry);
+ }
+
+ if (deviceObject != NULL) {
+ if (srbListInitialized) {
+ ExDeleteNPagedLookasideList(&deviceExtension->SrbLookasideListHead);
+ }
+ IoDeleteDevice(deviceObject);
+ }
+
+
+ return status;
+
+} // end CreateCdRomDeviceObject()
+
+\f
+VOID
+STDCALL
+ScsiCdRomStartIo(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+{
+
+ PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
+ PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
+ PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
+ PIO_STACK_LOCATION irpStack;
+ PIRP irp2 = NULL;
+ ULONG transferPages;
+ ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
+ ULONG maximumTransferLength = deviceExtension->PortCapabilities->MaximumTransferLength;
+ LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
+ PCDROM_DATA cdData;
+ PSCSI_REQUEST_BLOCK srb = NULL;
+ PCDB cdb;
+ PUCHAR senseBuffer = NULL;
+ PVOID dataBuffer;
+ NTSTATUS status;
+ BOOLEAN use6Byte;
+
+ //
+ // Mark IRP with status pending.
+ //
+
+ IoMarkIrpPending(Irp);
+
+ //
+ // If the flag is set in the device object, force a verify.
+ //
+
+ if (DeviceObject->Flags & DO_VERIFY_VOLUME) {
+ DebugPrint((2, "ScsiCdRomStartIo: [%lx] Volume needs verified\n", Irp));
+ if (!(currentIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME)) {
+
+ if (Irp->Tail.Overlay.Thread) {
+ IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
+ }
+
+ Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
+
+ DebugPrint((2, "ScsiCdRomStartIo: [%lx] Calling UpdateCapcity - "
+ "ioctl event = %lx\n",
+ Irp,
+ nextIrpStack->Parameters.Others.Argument1
+ ));
+
+ //
+ // our device control dispatch routine stores an event in the next
+ // stack location to signal when startio has completed. We need to
+ // pass this in so that the update capacity completion routine can
+ // set it rather than completing the Irp.
+ //
+
+ status = CdRomUpdateCapacity(deviceExtension,
+ Irp,
+ nextIrpStack->Parameters.Others.Argument1
+ );
+
+ DebugPrint((2, "ScsiCdRomStartIo: [%lx] UpdateCapacity returned %lx\n", Irp, status));
+ ASSERT(status == STATUS_PENDING);
+ return;
+ }
+ }
+
+ cdData = (PCDROM_DATA)(deviceExtension + 1);
+ use6Byte = cdData->XAFlags & XA_USE_6_BYTE;
+
+ if (currentIrpStack->MajorFunction == IRP_MJ_READ) {
+
+ //
+ // Add partition byte offset to make starting byte relative to
+ // beginning of disk. In addition, add in skew for DM Driver, if any.
+ //
+
+ currentIrpStack->Parameters.Read.ByteOffset.QuadPart += (deviceExtension->StartingOffset.QuadPart);
+
+ //
+ // Calculate number of pages in this transfer.
+ //
+
+ transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress),
+ currentIrpStack->Parameters.Read.Length);
+
+ //
+ // Check if request length is greater than the maximum number of
+ // bytes that the hardware can transfer.
+ //
+
+ if (cdData->RawAccess) {
+
+ ASSERT(!(cdData->XAFlags & XA_USE_READ_CD));
+
+ //
+ // Fire off a mode select to switch back to cooked sectors.
+ //
+
+ irp2 = IoAllocateIrp((CCHAR)(deviceExtension->DeviceObject->StackSize+1),
+ FALSE);
+
+ if (!irp2) {
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+ IoStartNextPacket(DeviceObject, FALSE);
+ return;
+ }
+
+ srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
+ if (!srb) {
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+ IoFreeIrp(irp2);
+ IoStartNextPacket(DeviceObject, FALSE);
+ return;
+ }
+
+ RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
+
+ cdb = (PCDB)srb->Cdb;
+
+ //
+ // Allocate sense buffer.
+ //
+
+ senseBuffer = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
+
+ if (!senseBuffer) {
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+ ExFreePool(srb);
+ IoFreeIrp(irp2);
+ IoStartNextPacket(DeviceObject, FALSE);
+ return;
+ }
+
+ //
+ // Set up the irp.
+ //
+
+ IoSetNextIrpStackLocation(irp2);
+ irp2->IoStatus.Status = STATUS_SUCCESS;
+ irp2->IoStatus.Information = 0;
+ irp2->Flags = 0;
+ irp2->UserBuffer = NULL;
+
+ //
+ // Save the device object and irp in a private stack location.
+ //
+
+ irpStack = IoGetCurrentIrpStackLocation(irp2);
+ irpStack->DeviceObject = deviceExtension->DeviceObject;
+ irpStack->Parameters.Others.Argument2 = (PVOID) Irp;
+
+ //
+ // The retry count will be in the real Irp, as the retry logic will
+ // recreate our private irp.
+ //
+
+ if (!(nextIrpStack->Parameters.Others.Argument1)) {
+
+ //
+ // Only jam this in if it doesn't exist. The completion routines can
+ // call StartIo directly in the case of retries and resetting it will
+ // cause infinite loops.
+ //
+
+ nextIrpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
+ }
+
+ //
+ // Construct the IRP stack for the lower level driver.
+ //
+
+ irpStack = IoGetNextIrpStackLocation(irp2);
+ irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
+ irpStack->Parameters.Scsi.Srb = srb;
+
+ srb->Length = SCSI_REQUEST_BLOCK_SIZE;
+ srb->PathId = deviceExtension->PathId;
+ srb->TargetId = deviceExtension->TargetId;
+ srb->Lun = deviceExtension->Lun;
+ srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
+ srb->Cdb[1] |= deviceExtension->Lun << 5;
+ srb->SrbStatus = srb->ScsiStatus = 0;
+ srb->NextSrb = 0;
+ srb->OriginalRequest = irp2;
+ srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
+ srb->SenseInfoBuffer = senseBuffer;
+
+ transferByteCount = (use6Byte) ? sizeof(ERROR_RECOVERY_DATA) : sizeof(ERROR_RECOVERY_DATA10);
+ dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, transferByteCount );
+ if (!dataBuffer) {
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+ ExFreePool(senseBuffer);
+ ExFreePool(srb);
+ IoFreeIrp(irp2);
+ IoStartNextPacket(DeviceObject, FALSE);
+ return;
+
+ }
+
+ irp2->MdlAddress = IoAllocateMdl(dataBuffer,
+ transferByteCount,
+ FALSE,
+ FALSE,
+ (PIRP) NULL);
+
+ if (!irp2->MdlAddress) {
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+ ExFreePool(senseBuffer);
+ ExFreePool(srb);
+ ExFreePool(dataBuffer);
+ IoFreeIrp(irp2);
+ IoStartNextPacket(DeviceObject, FALSE);
+ return;
+ }
+
+ //
+ // Prepare the MDL
+ //
+
+ MmBuildMdlForNonPagedPool(irp2->MdlAddress);
+
+ srb->DataBuffer = dataBuffer;
+
+ //
+ // Set the new block size in the descriptor.
+ //
+
+ cdData->u1.BlockDescriptor.BlockLength[0] = (UCHAR)(COOKED_SECTOR_SIZE >> 16) & 0xFF;
+ cdData->u1.BlockDescriptor.BlockLength[1] = (UCHAR)(COOKED_SECTOR_SIZE >> 8) & 0xFF;
+ cdData->u1.BlockDescriptor.BlockLength[2] = (UCHAR)(COOKED_SECTOR_SIZE & 0xFF);
+
+ //
+ // Move error page into dataBuffer.
+ //
+
+ RtlCopyMemory(srb->DataBuffer, &cdData->u1.Header, transferByteCount);
+
+ //
+ // Build and send a mode select to switch into raw mode.
+ //
+
+ srb->SrbFlags = deviceExtension->SrbFlags;
+ srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_OUT);
+ srb->DataTransferLength = transferByteCount;
+ srb->TimeOutValue = deviceExtension->TimeOutValue * 2;
+
+ if (use6Byte) {
+ srb->CdbLength = 6;
+ cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
+ cdb->MODE_SELECT.PFBit = 1;
+ cdb->MODE_SELECT.ParameterListLength = (UCHAR)transferByteCount;
+ } else {
+
+ srb->CdbLength = 10;
+ cdb->MODE_SELECT10.OperationCode = SCSIOP_MODE_SELECT10;
+ cdb->MODE_SELECT10.PFBit = 1;
+ cdb->MODE_SELECT10.ParameterListLength[0] = (UCHAR)(transferByteCount >> 8);
+ cdb->MODE_SELECT10.ParameterListLength[1] = (UCHAR)(transferByteCount & 0xFF);
+ }
+
+ //
+ // Update completion routine.
+ //
+
+ IoSetCompletionRoutine(irp2,
+ CdRomSwitchModeCompletion,
+ srb,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ IoCallDriver(deviceExtension->PortDeviceObject, irp2);
+ return;
+ }
+
+ if ((currentIrpStack->Parameters.Read.Length > maximumTransferLength) ||
+ (transferPages >
+ deviceExtension->PortCapabilities->MaximumPhysicalPages)) {
+
+ //
+ // Request needs to be split. Completion of each portion of the
+ // request will fire off the next portion. The final request will
+ // signal Io to send a new request.
+ //
+
+ transferPages =
+ deviceExtension->PortCapabilities->MaximumPhysicalPages - 1;
+
+ if(maximumTransferLength > transferPages << PAGE_SHIFT) {
+ maximumTransferLength = transferPages << PAGE_SHIFT;
+ }
+
+ //
+ // Check that the maximum transfer size is not zero
+ //
+
+ if(maximumTransferLength == 0) {
+ maximumTransferLength = PAGE_SIZE;
+ }
+
+ ScsiClassSplitRequest(DeviceObject, Irp, maximumTransferLength);
+ return;
+
+ } else {
+
+ //
+ // Build SRB and CDB for this IRP.
+ //
+
+ ScsiClassBuildRequest(DeviceObject, Irp);
+
+ }
+
+
+ } else if (currentIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
+
+ //
+ // Allocate an irp, srb and associated structures.
+ //
+
+ irp2 = IoAllocateIrp((CCHAR)(deviceExtension->DeviceObject->StackSize+1),
+ FALSE);
+
+ if (!irp2) {
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+ IoStartNextPacket(DeviceObject, FALSE);
+ DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp, Irp->IoStatus.Status, __LINE__));
+ return;
+ }
+
+ srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
+ if (!srb) {
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+ IoFreeIrp(irp2);
+ IoStartNextPacket(DeviceObject, FALSE);
+ DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp, Irp->IoStatus.Status, __LINE__));
+ return;
+ }
+
+ RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
+
+ cdb = (PCDB)srb->Cdb;
+
+ //
+ // Allocate sense buffer.
+ //
+
+ senseBuffer = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
+
+ if (!senseBuffer) {
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+ ExFreePool(srb);
+ IoFreeIrp(irp2);
+ IoStartNextPacket(DeviceObject, FALSE);
+ DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp, Irp->IoStatus.Status, __LINE__));
+ return;
+ }
+
+ //
+ // Set up the irp.
+ //
+
+ IoSetNextIrpStackLocation(irp2);
+ irp2->IoStatus.Status = STATUS_SUCCESS;
+ irp2->IoStatus.Information = 0;
+ irp2->Flags = 0;
+ irp2->UserBuffer = NULL;
+
+ //
+ // Save the device object and irp in a private stack location.
+ //
+
+ irpStack = IoGetCurrentIrpStackLocation(irp2);
+ irpStack->DeviceObject = deviceExtension->DeviceObject;
+ irpStack->Parameters.Others.Argument2 = (PVOID) Irp;
+
+ //
+ // The retry count will be in the real Irp, as the retry logic will
+ // recreate our private irp.
+ //
+
+ if (!(nextIrpStack->Parameters.Others.Argument1)) {
+
+ //
+ // Only jam this in if it doesn't exist. The completion routines can
+ // call StartIo directly in the case of retries and resetting it will
+ // cause infinite loops.
+ //
+
+ nextIrpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
+ }
+
+ //
+ // Construct the IRP stack for the lower level driver.
+ //
+
+ irpStack = IoGetNextIrpStackLocation(irp2);
+ irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
+ irpStack->Parameters.Scsi.Srb = srb;
+
+ IoSetCompletionRoutine(irp2,
+ CdRomDeviceControlCompletion,
+ srb,
+ TRUE,
+ TRUE,
+ TRUE);
+ //
+ // Setup those fields that are generic to all requests.
+ //
+
+ srb->Length = SCSI_REQUEST_BLOCK_SIZE;
+ srb->PathId = deviceExtension->PathId;
+ srb->TargetId = deviceExtension->TargetId;
+ srb->Lun = deviceExtension->Lun;
+ srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
+ srb->Cdb[1] |= deviceExtension->Lun << 5;
+ srb->SrbStatus = srb->ScsiStatus = 0;
+ srb->NextSrb = 0;
+ srb->OriginalRequest = irp2;
+ srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
+ srb->SenseInfoBuffer = senseBuffer;
+
+ switch (currentIrpStack->Parameters.DeviceIoControl.IoControlCode) {
+
+ case IOCTL_CDROM_RAW_READ: {
+
+ //
+ // Determine whether the drive is currently in raw or cooked mode,
+ // and which command to use to read the data.
+ //
+
+ if (!(cdData->XAFlags & XA_USE_READ_CD)) {
+
+ PRAW_READ_INFO rawReadInfo =
+ (PRAW_READ_INFO)currentIrpStack->Parameters.DeviceIoControl.Type3InputBuffer;
+ ULONG maximumTransferLength;
+ ULONG transferPages;
+
+ if (cdData->RawAccess) {
+
+ ULONG startingSector;
+ UCHAR min, sec, frame;
+
+ //
+ // Free the recently allocated irp, as we don't need it.
+ //
+
+ IoFreeIrp(irp2);
+
+ cdb = (PCDB)srb->Cdb;
+ RtlZeroMemory(cdb, 12);
+
+ //
+ // Calculate starting offset.
+ //
+
+ startingSector = (ULONG)(rawReadInfo->DiskOffset.QuadPart >> deviceExtension->SectorShift);
+ transferByteCount = rawReadInfo->SectorCount * RAW_SECTOR_SIZE;
+ maximumTransferLength = deviceExtension->PortCapabilities->MaximumTransferLength;
+ transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress),
+ transferByteCount);
+
+ //
+ // Determine if request is within limits imposed by miniport.
+ //
+
+ if (transferByteCount > maximumTransferLength ||
+ transferPages > deviceExtension->PortCapabilities->MaximumPhysicalPages) {
+
+ //
+ // The claim is that this won't happen, and is backed up by
+ // ActiveMovie usage, which does unbuffered XA reads of 0x18000, yet
+ // we get only 4 sector requests.
+ //
+
+
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+ ExFreePool(senseBuffer);
+ ExFreePool(srb);
+ IoStartNextPacket(DeviceObject, FALSE);
+ return;
+
+ }
+
+ srb->OriginalRequest = Irp;
+ srb->SrbFlags = deviceExtension->SrbFlags;
+ srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
+ srb->DataTransferLength = transferByteCount;
+ srb->TimeOutValue = deviceExtension->TimeOutValue;
+ srb->CdbLength = 10;
+ srb->DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
+
+ if (rawReadInfo->TrackMode == CDDA) {
+ if (cdData->XAFlags & PLEXTOR_CDDA) {
+
+ srb->CdbLength = 12;
+
+ cdb->PLXTR_READ_CDDA.LogicalUnitNumber = deviceExtension->Lun;
+ cdb->PLXTR_READ_CDDA.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
+ cdb->PLXTR_READ_CDDA.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
+ cdb->PLXTR_READ_CDDA.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
+ cdb->PLXTR_READ_CDDA.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
+
+ cdb->PLXTR_READ_CDDA.TransferBlockByte3 = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
+ cdb->PLXTR_READ_CDDA.TransferBlockByte2 = (UCHAR) (rawReadInfo->SectorCount >> 8);
+ cdb->PLXTR_READ_CDDA.TransferBlockByte1 = 0;
+ cdb->PLXTR_READ_CDDA.TransferBlockByte0 = 0;
+
+ cdb->PLXTR_READ_CDDA.SubCode = 0;
+ cdb->PLXTR_READ_CDDA.OperationCode = 0xD8;
+
+ } else if (cdData->XAFlags & NEC_CDDA) {
+
+ cdb->NEC_READ_CDDA.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
+ cdb->NEC_READ_CDDA.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
+ cdb->NEC_READ_CDDA.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
+ cdb->NEC_READ_CDDA.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
+
+ cdb->NEC_READ_CDDA.TransferBlockByte1 = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
+ cdb->NEC_READ_CDDA.TransferBlockByte0 = (UCHAR) (rawReadInfo->SectorCount >> 8);
+
+ cdb->NEC_READ_CDDA.OperationCode = 0xD4;
+ }
+ } else {
+
+ cdb->CDB10.LogicalUnitNumber = deviceExtension->Lun;
+
+ cdb->CDB10.TransferBlocksMsb = (UCHAR) (rawReadInfo->SectorCount >> 8);
+ cdb->CDB10.TransferBlocksLsb = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
+
+ cdb->CDB10.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
+ cdb->CDB10.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
+ cdb->CDB10.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
+ cdb->CDB10.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
+
+ cdb->CDB10.OperationCode = SCSIOP_READ;
+ }
+
+ srb->SrbStatus = srb->ScsiStatus = 0;
+
+ nextIrpStack->MajorFunction = IRP_MJ_SCSI;
+ nextIrpStack->Parameters.Scsi.Srb = srb;
+
+ if (!(nextIrpStack->Parameters.Others.Argument1)) {
+
+ //
+ // Only jam this in if it doesn't exist. The completion routines can
+ // call StartIo directly in the case of retries and resetting it will
+ // cause infinite loops.
+ //
+
+ nextIrpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
+ }
+
+ //
+ // Set up IoCompletion routine address.
+ //
+
+ IoSetCompletionRoutine(Irp,
+ CdRomXACompletion,
+ srb,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ IoCallDriver(deviceExtension->PortDeviceObject, Irp);
+ return;
+
+ } else {
+
+ transferByteCount = (use6Byte) ? sizeof(ERROR_RECOVERY_DATA) : sizeof(ERROR_RECOVERY_DATA10);
+ dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, transferByteCount );
+ if (!dataBuffer) {
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+ ExFreePool(senseBuffer);
+ ExFreePool(srb);
+ IoFreeIrp(irp2);
+ IoStartNextPacket(DeviceObject, FALSE);
+ return;
+
+ }
+
+ irp2->MdlAddress = IoAllocateMdl(dataBuffer,
+ transferByteCount,
+ FALSE,
+ FALSE,
+ (PIRP) NULL);
+
+ if (!irp2->MdlAddress) {
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+ ExFreePool(senseBuffer);
+ ExFreePool(srb);
+ ExFreePool(dataBuffer);
+ IoFreeIrp(irp2);
+ IoStartNextPacket(DeviceObject, FALSE);
+ return;
+ }
+
+ //
+ // Prepare the MDL
+ //
+
+ MmBuildMdlForNonPagedPool(irp2->MdlAddress);
+
+ srb->DataBuffer = dataBuffer;
+
+ //
+ // Set the new block size in the descriptor.
+ //
+
+ cdData->u1.BlockDescriptor.BlockLength[0] = (UCHAR)(RAW_SECTOR_SIZE >> 16) & 0xFF;
+ cdData->u1.BlockDescriptor.BlockLength[1] = (UCHAR)(RAW_SECTOR_SIZE >> 8) & 0xFF;
+ cdData->u1.BlockDescriptor.BlockLength[2] = (UCHAR)(RAW_SECTOR_SIZE & 0xFF);
+
+
+ //
+ // TODO: Set density code, based on operation
+ //
+
+ cdData->u1.BlockDescriptor.DensityCode = 0;
+
+
+ //
+ // Move error page into dataBuffer.
+ //
+
+ RtlCopyMemory(srb->DataBuffer, &cdData->u1.Header, transferByteCount);
+
+
+ //
+ // Build and send a mode select to switch into raw mode.
+ //
+
+ srb->SrbFlags = deviceExtension->SrbFlags;
+ srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_OUT);
+ srb->DataTransferLength = transferByteCount;
+ srb->TimeOutValue = deviceExtension->TimeOutValue * 2;
+
+ if (use6Byte) {
+ srb->CdbLength = 6;
+ cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
+ cdb->MODE_SELECT.PFBit = 1;
+ cdb->MODE_SELECT.ParameterListLength = (UCHAR)transferByteCount;
+ } else {
+
+ srb->CdbLength = 10;
+ cdb->MODE_SELECT10.OperationCode = SCSIOP_MODE_SELECT10;
+ cdb->MODE_SELECT10.PFBit = 1;
+ cdb->MODE_SELECT10.ParameterListLength[0] = (UCHAR)(transferByteCount >> 8);
+ cdb->MODE_SELECT10.ParameterListLength[1] = (UCHAR)(transferByteCount & 0xFF);
+ }
+
+ //
+ // Update completion routine.
+ //
+
+ IoSetCompletionRoutine(irp2,
+ CdRomSwitchModeCompletion,
+ srb,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ }
+
+ } else {
+
+ PRAW_READ_INFO rawReadInfo =
+ (PRAW_READ_INFO)currentIrpStack->Parameters.DeviceIoControl.Type3InputBuffer;
+ ULONG startingSector;
+
+ //
+ // Free the recently allocated irp, as we don't need it.
+ //
+
+ IoFreeIrp(irp2);
+
+ cdb = (PCDB)srb->Cdb;
+ RtlZeroMemory(cdb, 12);
+
+
+ //
+ // Calculate starting offset.
+ //
+
+ startingSector = (ULONG)(rawReadInfo->DiskOffset.QuadPart >> deviceExtension->SectorShift);
+ transferByteCount = rawReadInfo->SectorCount * RAW_SECTOR_SIZE;
+
+
+ srb->OriginalRequest = Irp;
+ srb->SrbFlags = deviceExtension->SrbFlags;
+ srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
+ srb->DataTransferLength = transferByteCount;
+ srb->TimeOutValue = deviceExtension->TimeOutValue;
+ srb->DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
+ srb->CdbLength = 12;
+ srb->SrbStatus = srb->ScsiStatus = 0;
+
+ //
+ // Fill in CDB fields.
+ //
+
+ cdb = (PCDB)srb->Cdb;
+
+
+ cdb->READ_CD.TransferBlocks[2] = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
+ cdb->READ_CD.TransferBlocks[1] = (UCHAR) (rawReadInfo->SectorCount >> 8 );
+ cdb->READ_CD.TransferBlocks[0] = (UCHAR) (rawReadInfo->SectorCount >> 16);
+
+
+ cdb->READ_CD.StartingLBA[3] = (UCHAR) (startingSector & 0xFF);
+ cdb->READ_CD.StartingLBA[2] = (UCHAR) ((startingSector >> 8));
+ cdb->READ_CD.StartingLBA[1] = (UCHAR) ((startingSector >> 16));
+ cdb->READ_CD.StartingLBA[0] = (UCHAR) ((startingSector >> 24));
+
+ //
+ // Setup cdb depending upon the sector type we want.
+ //
+
+ switch (rawReadInfo->TrackMode) {
+ case CDDA:
+
+ cdb->READ_CD.ExpectedSectorType = CD_DA_SECTOR;
+ cdb->READ_CD.IncludeUserData = 1;
+ cdb->READ_CD.HeaderCode = 3;
+ cdb->READ_CD.IncludeSyncData = 1;
+ break;
+
+ case YellowMode2:
+
+ cdb->READ_CD.ExpectedSectorType = YELLOW_MODE2_SECTOR;
+ cdb->READ_CD.IncludeUserData = 1;
+ cdb->READ_CD.HeaderCode = 1;
+ cdb->READ_CD.IncludeSyncData = 1;
+ break;
+
+ case XAForm2:
+
+ cdb->READ_CD.ExpectedSectorType = FORM2_MODE2_SECTOR;
+ cdb->READ_CD.IncludeUserData = 1;
+ cdb->READ_CD.HeaderCode = 3;
+ cdb->READ_CD.IncludeSyncData = 1;
+ break;
+
+ default:
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+ ExFreePool(senseBuffer);
+ ExFreePool(srb);
+ IoFreeIrp(irp2);
+ IoStartNextPacket(DeviceObject, FALSE);
+ DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp, Irp->IoStatus.Status, __LINE__));
+ return;
+ }
+
+ cdb->READ_CD.OperationCode = SCSIOP_READ_CD;
+
+ nextIrpStack->MajorFunction = IRP_MJ_SCSI;
+ nextIrpStack->Parameters.Scsi.Srb = srb;
+
+ if (!(nextIrpStack->Parameters.Others.Argument1)) {
+
+ //
+ // Only jam this in if it doesn't exist. The completion routines can
+ // call StartIo directly in the case of retries and resetting it will
+ // cause infinite loops.
+ //
+
+ nextIrpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
+ }
+
+ //
+ // Set up IoCompletion routine address.
+ //
+
+ IoSetCompletionRoutine(Irp,
+ CdRomXACompletion,
+ srb,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ IoCallDriver(deviceExtension->PortDeviceObject, Irp);
+ return;
+
+ }
+
+ IoCallDriver(deviceExtension->PortDeviceObject, irp2);
+ return;
+ }
+
+ case IOCTL_CDROM_GET_DRIVE_GEOMETRY: {
+
+ //
+ // Issue ReadCapacity to update device extension
+ // with information for current media.
+ //
+
+ DebugPrint((3,
+ "CdRomStartIo: Get drive capacity\n"));
+
+ //
+ // setup remaining srb and cdb parameters.
+ //
+
+ srb->SrbFlags = deviceExtension->SrbFlags;
+ srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
+ srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
+ srb->CdbLength = 10;
+ srb->TimeOutValue = deviceExtension->TimeOutValue;
+
+ dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, sizeof(READ_CAPACITY_DATA));
+ if (!dataBuffer) {
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+ ExFreePool(senseBuffer);
+ ExFreePool(srb);
+ IoFreeIrp(irp2);
+ IoStartNextPacket(DeviceObject, FALSE);
+ DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp, Irp->IoStatus.Status, __LINE__));
+ return;
+
+ }
+
+ irp2->MdlAddress = IoAllocateMdl(dataBuffer,
+ sizeof(READ_CAPACITY_DATA),
+ FALSE,
+ FALSE,
+ (PIRP) NULL);
+
+ if (!irp2->MdlAddress) {
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+ ExFreePool(senseBuffer);
+ ExFreePool(srb);
+ ExFreePool(dataBuffer);
+ IoFreeIrp(irp2);
+ IoStartNextPacket(DeviceObject, FALSE);
+ DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp, Irp->IoStatus.Status, __LINE__));
+ return;
+ }
+
+ //
+ // Prepare the MDL
+ //
+
+ MmBuildMdlForNonPagedPool(irp2->MdlAddress);
+
+ srb->DataBuffer = dataBuffer;
+ cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
+
+ IoCallDriver(deviceExtension->PortDeviceObject, irp2);
+ return;
+ }
+
+ case IOCTL_CDROM_CHECK_VERIFY: {
+
+ //
+ // Since a test unit ready is about to be performed, reset the timer
+ // value to decrease the opportunities for it to race with this code.
+ //
+
+ cdData->MediaChangeCountDown = MEDIA_CHANGE_DEFAULT_TIME;
+
+ //
+ // Set up the SRB/CDB
+ //
+
+ srb->CdbLength = 6;
+ cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
+ srb->TimeOutValue = deviceExtension->TimeOutValue * 2;
+ srb->SrbFlags = deviceExtension->SrbFlags;
+ srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER);
+
+ DebugPrint((2, "ScsiCdRomStartIo: [%lx] Sending CHECK_VERIFY irp %lx\n", Irp, irp2));
+ IoCallDriver(deviceExtension->PortDeviceObject, irp2);
+ return;
+ }
+
+ case IOCTL_CDROM_GET_LAST_SESSION:
+
+ //
+ // Set format to return first and last session numbers.
+ //
+
+ cdb->READ_TOC.Format = GET_LAST_SESSION;
+
+ //
+ // Fall through to READ TOC code.
+ //
+
+ case IOCTL_CDROM_READ_TOC: {
+
+
+ if (currentIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_READ_TOC) {
+
+ //
+ // Use MSF addressing if not request for session information.
+ //
+
+ cdb->READ_TOC.Msf = CDB_USE_MSF;
+ }
+
+ //
+ // Set size of TOC structure.
+ //
+
+ transferByteCount =
+ currentIrpStack->Parameters.Read.Length >
+ sizeof(CDROM_TOC) ? sizeof(CDROM_TOC):
+ currentIrpStack->Parameters.Read.Length;
+
+ cdb->READ_TOC.AllocationLength[0] = (UCHAR) (transferByteCount >> 8);
+ cdb->READ_TOC.AllocationLength[1] = (UCHAR) (transferByteCount & 0xFF);
+
+ cdb->READ_TOC.Control = 0;
+
+ //
+ // Start at beginning of disc.
+ //
+
+ cdb->READ_TOC.StartingTrack = 0;
+
+ //
+ // setup remaining srb and cdb parameters.
+ //
+
+ srb->SrbFlags = deviceExtension->SrbFlags;
+ srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
+ srb->DataTransferLength = transferByteCount;
+ srb->CdbLength = 10;
+ srb->TimeOutValue = deviceExtension->TimeOutValue;
+
+ dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, transferByteCount);
+ if (!dataBuffer) {
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+ ExFreePool(senseBuffer);
+ ExFreePool(srb);
+ IoFreeIrp(irp2);
+ IoStartNextPacket(DeviceObject, FALSE);
+ return;
+
+ }
+
+ irp2->MdlAddress = IoAllocateMdl(dataBuffer,
+ transferByteCount,
+ FALSE,
+ FALSE,
+ (PIRP) NULL);
+
+ if (!irp2->MdlAddress) {
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+ ExFreePool(senseBuffer);
+ ExFreePool(srb);
+ ExFreePool(dataBuffer);
+ IoFreeIrp(irp2);
+ IoStartNextPacket(DeviceObject, FALSE);
+ return;
+ }
+
+ //
+ // Prepare the MDL
+ //
+
+ MmBuildMdlForNonPagedPool(irp2->MdlAddress);
+
+ srb->DataBuffer = dataBuffer;
+ cdb->READ_TOC.OperationCode = SCSIOP_READ_TOC;
+
+ IoCallDriver(deviceExtension->PortDeviceObject, irp2);
+ return;
+
+ }
+
+ case IOCTL_CDROM_PLAY_AUDIO_MSF: {
+
+ PCDROM_PLAY_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
+
+ //
+ // Set up the SRB/CDB
+ //
+
+ srb->CdbLength = 10;
+ cdb->PLAY_AUDIO_MSF.OperationCode = SCSIOP_PLAY_AUDIO_MSF;
+
+ cdb->PLAY_AUDIO_MSF.StartingM = inputBuffer->StartingM;
+ cdb->PLAY_AUDIO_MSF.StartingS = inputBuffer->StartingS;
+ cdb->PLAY_AUDIO_MSF.StartingF = inputBuffer->StartingF;
+
+ cdb->PLAY_AUDIO_MSF.EndingM = inputBuffer->EndingM;
+ cdb->PLAY_AUDIO_MSF.EndingS = inputBuffer->EndingS;
+ cdb->PLAY_AUDIO_MSF.EndingF = inputBuffer->EndingF;
+
+ srb->TimeOutValue = deviceExtension->TimeOutValue;
+ srb->SrbFlags = deviceExtension->SrbFlags;
+ srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER);
+
+ IoCallDriver(deviceExtension->PortDeviceObject, irp2);
+ return;
+
+ }
+
+ case IOCTL_CDROM_READ_Q_CHANNEL: {
+
+ PSUB_Q_CHANNEL_DATA userChannelData =
+ Irp->AssociatedIrp.SystemBuffer;
+ PCDROM_SUB_Q_DATA_FORMAT inputBuffer =
+ Irp->AssociatedIrp.SystemBuffer;
+
+ //
+ // Allocate buffer for subq channel information.
+ //
+
+ dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
+ sizeof(SUB_Q_CHANNEL_DATA));
+
+ if (!dataBuffer) {
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+ ExFreePool(senseBuffer);
+ ExFreePool(srb);
+ IoFreeIrp(irp2);
+ IoStartNextPacket(DeviceObject, FALSE);
+ return;
+
+ }
+
+ irp2->MdlAddress = IoAllocateMdl(dataBuffer,
+ transferByteCount,
+ FALSE,
+ FALSE,
+ (PIRP) NULL);
+
+ if (!irp2->MdlAddress) {
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+ ExFreePool(senseBuffer);
+ ExFreePool(srb);
+ ExFreePool(dataBuffer);
+ IoFreeIrp(irp2);
+ IoStartNextPacket(DeviceObject, FALSE);
+ return;
+ }
+
+ //
+ // Prepare the MDL
+ //
+
+ MmBuildMdlForNonPagedPool(irp2->MdlAddress);
+
+ srb->DataBuffer = dataBuffer;
+
+ //
+ // Always logical unit 0, but only use MSF addressing
+ // for IOCTL_CDROM_CURRENT_POSITION
+ //
+
+ if (inputBuffer->Format==IOCTL_CDROM_CURRENT_POSITION)
+ cdb->SUBCHANNEL.Msf = CDB_USE_MSF;
+
+ //
+ // Return subchannel data
+ //
+
+ cdb->SUBCHANNEL.SubQ = CDB_SUBCHANNEL_BLOCK;
+
+ //
+ // Specify format of informatin to return
+ //
+
+ cdb->SUBCHANNEL.Format = inputBuffer->Format;
+
+ //
+ // Specify which track to access (only used by Track ISRC reads)
+ //
+
+ if (inputBuffer->Format==IOCTL_CDROM_TRACK_ISRC) {
+ cdb->SUBCHANNEL.TrackNumber = inputBuffer->Track;
+ }
+
+ //
+ // Set size of channel data -- however, this is dependent on
+ // what information we are requesting (which Format)
+ //
+
+ switch( inputBuffer->Format ) {
+
+ case IOCTL_CDROM_CURRENT_POSITION:
+ transferByteCount = sizeof(SUB_Q_CURRENT_POSITION);
+ break;
+
+ case IOCTL_CDROM_MEDIA_CATALOG:
+ transferByteCount = sizeof(SUB_Q_MEDIA_CATALOG_NUMBER);
+ break;
+
+ case IOCTL_CDROM_TRACK_ISRC:
+ transferByteCount = sizeof(SUB_Q_TRACK_ISRC);
+ break;
+ }
+
+ cdb->SUBCHANNEL.AllocationLength[0] = (UCHAR) (transferByteCount >> 8);
+ cdb->SUBCHANNEL.AllocationLength[1] = (UCHAR) (transferByteCount & 0xFF);
+ cdb->SUBCHANNEL.OperationCode = SCSIOP_READ_SUB_CHANNEL;
+ srb->SrbFlags = deviceExtension->SrbFlags;
+ srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
+ srb->DataTransferLength = transferByteCount;
+ srb->CdbLength = 10;
+ srb->TimeOutValue = deviceExtension->TimeOutValue;
+
+ IoCallDriver(deviceExtension->PortDeviceObject, irp2);
+ return;
+
+ }
+
+ case IOCTL_CDROM_PAUSE_AUDIO: {
+
+ cdb->PAUSE_RESUME.OperationCode = SCSIOP_PAUSE_RESUME;
+ cdb->PAUSE_RESUME.Action = CDB_AUDIO_PAUSE;
+
+ srb->CdbLength = 10;
+ srb->TimeOutValue = deviceExtension->TimeOutValue;
+ srb->SrbFlags = deviceExtension->SrbFlags;
+ srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER);
+
+ IoCallDriver(deviceExtension->PortDeviceObject, irp2);
+ return;
+ }
+
+ case IOCTL_CDROM_RESUME_AUDIO: {
+
+ cdb->PAUSE_RESUME.OperationCode = SCSIOP_PAUSE_RESUME;
+ cdb->PAUSE_RESUME.Action = CDB_AUDIO_RESUME;
+
+ srb->CdbLength = 10;
+ srb->TimeOutValue = deviceExtension->TimeOutValue;
+ srb->SrbFlags = deviceExtension->SrbFlags;
+ srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER);
+
+ IoCallDriver(deviceExtension->PortDeviceObject, irp2);
+ return;
+ }
+
+ case IOCTL_CDROM_SEEK_AUDIO_MSF: {
+
+ PCDROM_SEEK_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
+ ULONG logicalBlockAddress;
+
+ logicalBlockAddress = MSF_TO_LBA(inputBuffer->M, inputBuffer->S, inputBuffer->F);
+
+ cdb->SEEK.OperationCode = SCSIOP_SEEK;
+ cdb->SEEK.LogicalBlockAddress[0] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte3;
+ cdb->SEEK.LogicalBlockAddress[1] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte2;
+ cdb->SEEK.LogicalBlockAddress[2] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte1;
+ cdb->SEEK.LogicalBlockAddress[3] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte0;
+
+ srb->CdbLength = 10;
+ srb->TimeOutValue = deviceExtension->TimeOutValue;
+ srb->SrbFlags = deviceExtension->SrbFlags;
+ srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER);
+
+ IoCallDriver(deviceExtension->PortDeviceObject, irp2);
+ return;
+
+ }
+
+ case IOCTL_CDROM_STOP_AUDIO: {
+
+ cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
+ cdb->START_STOP.Immediate = 1;
+ cdb->START_STOP.Start = 0;
+ cdb->START_STOP.LoadEject = 0;
+
+ srb->CdbLength = 6;
+ srb->TimeOutValue = deviceExtension->TimeOutValue;
+
+ srb->SrbFlags = deviceExtension->SrbFlags;
+ srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER);
+
+ IoCallDriver(deviceExtension->PortDeviceObject, irp2);
+ return;
+ }
+
+ case IOCTL_CDROM_GET_CONTROL: {
+
+ PAUDIO_OUTPUT audioOutput;
+ PCDROM_AUDIO_CONTROL audioControl = Irp->AssociatedIrp.SystemBuffer;
+
+ //
+ // Allocate buffer for volume control information.
+ //
+
+ dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
+ MODE_DATA_SIZE);
+
+ if (!dataBuffer) {
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+ ExFreePool(senseBuffer);
+ ExFreePool(srb);
+ IoFreeIrp(irp2);
+ IoStartNextPacket(DeviceObject, FALSE);
+ return;
+
+ }
+
+ irp2->MdlAddress = IoAllocateMdl(dataBuffer,
+ MODE_DATA_SIZE,
+ FALSE,
+ FALSE,
+ (PIRP) NULL);
+
+ if (!irp2->MdlAddress) {
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+ ExFreePool(senseBuffer);
+ ExFreePool(srb);
+ ExFreePool(dataBuffer);
+ IoFreeIrp(irp2);
+ IoStartNextPacket(DeviceObject, FALSE);
+ return;
+ }
+
+ //
+ // Prepare the MDL
+ //
+
+ MmBuildMdlForNonPagedPool(irp2->MdlAddress);
+ srb->DataBuffer = dataBuffer;
+
+ RtlZeroMemory(dataBuffer, MODE_DATA_SIZE);
+
+ //
+ // Setup for either 6 or 10 byte CDBs.
+ //
+
+ if (use6Byte) {
+
+ cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
+ cdb->MODE_SENSE.PageCode = CDROM_AUDIO_CONTROL_PAGE;
+ cdb->MODE_SENSE.AllocationLength = MODE_DATA_SIZE;
+
+ //
+ // Disable block descriptors.
+ //
+
+ cdb->MODE_SENSE.Dbd = TRUE;
+
+ srb->CdbLength = 6;
+ } else {
+
+ cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
+ cdb->MODE_SENSE10.PageCode = CDROM_AUDIO_CONTROL_PAGE;
+ cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(MODE_DATA_SIZE >> 8);
+ cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(MODE_DATA_SIZE & 0xFF);
+
+ //
+ // Disable block descriptors.
+ //
+
+ cdb->MODE_SENSE10.Dbd = TRUE;
+
+ srb->CdbLength = 10;
+ }
+
+ srb->TimeOutValue = deviceExtension->TimeOutValue;
+ srb->DataTransferLength = MODE_DATA_SIZE;
+ srb->SrbFlags = deviceExtension->SrbFlags;
+ srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
+
+ IoCallDriver(deviceExtension->PortDeviceObject, irp2);
+ return;
+
+ }
+
+ case IOCTL_CDROM_GET_VOLUME:
+ case IOCTL_CDROM_SET_VOLUME: {
+
+ dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
+ MODE_DATA_SIZE);
+
+ if (!dataBuffer) {
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+ ExFreePool(senseBuffer);
+ ExFreePool(srb);
+ IoFreeIrp(irp2);
+ IoStartNextPacket(DeviceObject, FALSE);
+ return;
+ }
+
+ irp2->MdlAddress = IoAllocateMdl(dataBuffer,
+ MODE_DATA_SIZE,
+ FALSE,
+ FALSE,
+ (PIRP) NULL);
+
+ if (!irp2->MdlAddress) {
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+ ExFreePool(senseBuffer);
+ ExFreePool(srb);
+ ExFreePool(dataBuffer);
+ IoFreeIrp(irp2);
+ IoStartNextPacket(DeviceObject, FALSE);
+ return;
+ }
+
+ //
+ // Prepare the MDL
+ //
+
+ MmBuildMdlForNonPagedPool(irp2->MdlAddress);
+ srb->DataBuffer = dataBuffer;
+
+ RtlZeroMemory(dataBuffer, MODE_DATA_SIZE);
+
+
+ if (use6Byte) {
+ cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
+ cdb->MODE_SENSE.PageCode = CDROM_AUDIO_CONTROL_PAGE;
+ cdb->MODE_SENSE.AllocationLength = MODE_DATA_SIZE;
+
+ srb->CdbLength = 6;
+
+ } else {
+
+ cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
+ cdb->MODE_SENSE10.PageCode = CDROM_AUDIO_CONTROL_PAGE;
+ cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(MODE_DATA_SIZE >> 8);
+ cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(MODE_DATA_SIZE & 0xFF);
+
+ srb->CdbLength = 10;
+ }
+
+ srb->TimeOutValue = deviceExtension->TimeOutValue;
+ srb->DataTransferLength = MODE_DATA_SIZE;
+ srb->SrbFlags = deviceExtension->SrbFlags;
+ srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
+
+ if (currentIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_SET_VOLUME) {
+
+ //
+ // Setup a different completion routine as the mode sense data is needed in order
+ // to send the mode select.
+ //
+
+ IoSetCompletionRoutine(irp2,
+ CdRomSetVolumeIntermediateCompletion,
+ srb,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ }
+
+ IoCallDriver(deviceExtension->PortDeviceObject, irp2);
+ return;
+
+ }
+
+ default:
+
+ //
+ // Just complete the request - CdRomClassIoctlCompletion will take
+ // care of it for us
+ //
+
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return;
+
+ } // end switch()
+ }
+
+ //
+ // If a read or an unhandled IRP_MJ_XX, end up here. The unhandled IRP_MJ's
+ // are expected and composed of AutoRun Irps, at present.
+ //
+
+ IoCallDriver(deviceExtension->PortDeviceObject, Irp);
+ return;
+}
+
+
+\f
+NTSTATUS
+STDCALL
+ScsiCdRomReadVerification(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This is the entry called by the I/O system for read requests.
+ It builds the SRB and sends it to the port driver.
+
+Arguments:
+
+ DeviceObject - the system object for the device.
+ Irp - IRP involved.
+
+Return Value:
+
+ NT Status
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
+ PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
+ ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
+ LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
+ PCDROM_DATA cdData = (PCDROM_DATA)(deviceExtension+1);
+ KIRQL irql;
+ SCSI_REQUEST_BLOCK srb;
+ PCDB cdb = (PCDB)srb.Cdb;
+ NTSTATUS status;
+
+ //
+ // If the cd is playing music then reject this request.
+ //
+
+ if (PLAY_ACTIVE(deviceExtension)) {
+ Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
+ return STATUS_DEVICE_BUSY;
+ }
+
+ //
+ // Verify parameters of this request.
+ // Check that ending sector is on disc and
+ // that number of bytes to transfer is a multiple of
+ // the sector size.
+ //
+
+ startingOffset.QuadPart = currentIrpStack->Parameters.Read.ByteOffset.QuadPart +
+ transferByteCount;
+
+ if (!deviceExtension->DiskGeometry->BytesPerSector) {
+ deviceExtension->DiskGeometry->BytesPerSector = 2048;
+ }
+
+ if ((startingOffset.QuadPart > deviceExtension->PartitionLength.QuadPart) ||
+ (transferByteCount & deviceExtension->DiskGeometry->BytesPerSector - 1)) {
+
+ DebugPrint((1,"ScsiCdRomRead: Invalid I/O parameters\n"));
+ DebugPrint((1, "\toffset %x:%x, Length %x:%x\n",
+ startingOffset.u.HighPart,
+ startingOffset.u.LowPart,
+ deviceExtension->PartitionLength.u.HighPart,
+ deviceExtension->PartitionLength.u.LowPart));
+ DebugPrint((1, "\tbps %x\n", deviceExtension->DiskGeometry->BytesPerSector));
+
+ //
+ // Fail request with status of invalid parameters.
+ //
+
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+
+ return STATUS_INVALID_PARAMETER;
+ }
+
+
+ return STATUS_SUCCESS;
+
+} // end ScsiCdRomReadVerification()
+
+
+\f
+NTSTATUS
+STDCALL
+CdRomDeviceControlCompletion(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+{
+ PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
+ PDEVICE_EXTENSION physicalExtension = deviceExtension->PhysicalDevice->DeviceExtension;
+ PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
+ PCDROM_DATA cdData = (PCDROM_DATA)(deviceExtension + 1);
+ BOOLEAN use6Byte = cdData->XAFlags & XA_USE_6_BYTE;
+ PIO_STACK_LOCATION realIrpStack;
+ PIO_STACK_LOCATION realIrpNextStack;
+ PSCSI_REQUEST_BLOCK srb = Context;
+ PIRP realIrp = NULL;
+ NTSTATUS status;
+ BOOLEAN retry;
+
+ //
+ // Extract the 'real' irp from the irpstack.
+ //
+
+ realIrp = (PIRP) irpStack->Parameters.Others.Argument2;
+ realIrpStack = IoGetCurrentIrpStackLocation(realIrp);
+ realIrpNextStack = IoGetNextIrpStackLocation(realIrp);
+
+ //
+ // Check SRB status for success of completing request.
+ //
+
+ if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
+
+ DebugPrint((2,
+ "CdRomDeviceControlCompletion: Irp %lx, Srb %lx Real Irp %lx Status %lx\n",
+ Irp,
+ srb,
+ realIrp,
+ srb->SrbStatus));
+
+ //
+ // Release the queue if it is frozen.
+ //
+
+ if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
+ DebugPrint((2, "CdRomDeviceControlCompletion: Releasing Queue\n"));
+ ScsiClassReleaseQueue(DeviceObject);
+ }
+
+
+ retry = ScsiClassInterpretSenseInfo(DeviceObject,
+ srb,
+ irpStack->MajorFunction,
+ irpStack->Parameters.DeviceIoControl.IoControlCode,
+ MAXIMUM_RETRIES - ((ULONG)realIrpNextStack->Parameters.Others.Argument1),
+ &status);
+
+ DebugPrint((2, "CdRomDeviceControlCompletion: IRP will %sbe retried\n",
+ (retry ? "" : "not ")));
+
+ //
+ // Some of the Device Controls need special cases on non-Success status's.
+ //
+
+ if (realIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
+ if ((realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_GET_LAST_SESSION) ||
+ (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_READ_TOC) ||
+ (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_GET_CONTROL) ||
+ (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_GET_VOLUME)) {
+
+ if (status == STATUS_DATA_OVERRUN) {
+ status = STATUS_SUCCESS;
+ retry = FALSE;
+ }
+ }
+
+ if (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_READ_Q_CHANNEL) {
+ PLAY_ACTIVE(deviceExtension) = FALSE;
+ }
+ }
+
+ //
+ // If the status is verified required and the this request
+ // should bypass verify required then retry the request.
+ //
+
+ if (realIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
+ status == STATUS_VERIFY_REQUIRED) {
+
+ if (((realIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) ||
+ (realIrpStack->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL)) &&
+ (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_CHECK_VERIFY)) {
+
+ //
+ // Update the geometry information, as the media could have changed.
+ // The completion routine for this will complete the real irp and start
+ // the next packet.
+ //
+
+ status = CdRomUpdateCapacity(deviceExtension,realIrp, NULL);
+ DebugPrint((2, "CdRomDeviceControlCompletion: [%lx] CdRomUpdateCapacity completed with status %lx\n", realIrp, status));
+ ASSERT(status == STATUS_PENDING);
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+
+ } else {
+
+ status = STATUS_IO_DEVICE_ERROR;
+ retry = TRUE;
+ }
+
+ }
+
+ if (retry && (realIrpNextStack->Parameters.Others.Argument1 = (ULONG)realIrpNextStack->Parameters.Others.Argument1-1)) {
+
+
+ if (((ULONG)realIrpNextStack->Parameters.Others.Argument1)) {
+
+ //
+ // Retry request.
+ //
+
+ DebugPrint((1, "Retry request %lx - Calling StartIo\n", Irp));
+
+
+ ExFreePool(srb->SenseInfoBuffer);
+ if (srb->DataBuffer) {
+ ExFreePool(srb->DataBuffer);
+ }
+ ExFreePool(srb);
+ if (Irp->MdlAddress) {
+ IoFreeMdl(Irp->MdlAddress);
+ }
+
+ IoFreeIrp(Irp);
+
+ //
+ // Call StartIo directly since IoStartNextPacket hasn't been called,
+ // the serialisation is still intact.
+ //
+
+ ScsiCdRomStartIo(DeviceObject, realIrp);
+ return STATUS_MORE_PROCESSING_REQUIRED;
+
+ }
+
+ //
+ // Exhausted retries. Fall through and complete the request with the appropriate status.
+ //
+
+ }
+ } else {
+
+ //
+ // Set status for successful request.
+ //
+
+ status = STATUS_SUCCESS;
+ }
+
+ if (NT_SUCCESS(status)) {
+
+ switch (realIrpStack->Parameters.DeviceIoControl.IoControlCode) {
+
+ case IOCTL_CDROM_GET_DRIVE_GEOMETRY: {
+
+ PREAD_CAPACITY_DATA readCapacityBuffer = srb->DataBuffer;
+ ULONG lastSector;
+ ULONG bps;
+ ULONG lastBit;
+ ULONG tmp;
+
+ //
+ // Swizzle bytes from Read Capacity and translate into
+ // the necessary geometry information in the device extension.
+ //
+
+ tmp = readCapacityBuffer->BytesPerBlock;
+ ((PFOUR_BYTE)&bps)->Byte0 = ((PFOUR_BYTE)&tmp)->Byte3;
+ ((PFOUR_BYTE)&bps)->Byte1 = ((PFOUR_BYTE)&tmp)->Byte2;
+ ((PFOUR_BYTE)&bps)->Byte2 = ((PFOUR_BYTE)&tmp)->Byte1;
+ ((PFOUR_BYTE)&bps)->Byte3 = ((PFOUR_BYTE)&tmp)->Byte0;
+
+ //
+ // Insure that bps is a power of 2.
+ // This corrects a problem with the HP 4020i CDR where it
+ // returns an incorrect number for bytes per sector.
+ //
+
+ if (!bps) {
+ bps = 2048;
+ } else {
+ lastBit = (ULONG) -1;
+ while (bps) {
+ lastBit++;
+ bps = bps >> 1;
+ }
+
+ bps = 1 << lastBit;
+ }
+ deviceExtension->DiskGeometry->BytesPerSector = bps;
+
+ DebugPrint((2,
+ "CdRomDeviceControlCompletion: Calculated bps %#x\n",
+ deviceExtension->DiskGeometry->BytesPerSector));
+
+ //
+ // Copy last sector in reverse byte order.
+ //
+
+ tmp = readCapacityBuffer->LogicalBlockAddress;
+ ((PFOUR_BYTE)&lastSector)->Byte0 = ((PFOUR_BYTE)&tmp)->Byte3;
+ ((PFOUR_BYTE)&lastSector)->Byte1 = ((PFOUR_BYTE)&tmp)->Byte2;
+ ((PFOUR_BYTE)&lastSector)->Byte2 = ((PFOUR_BYTE)&tmp)->Byte1;
+ ((PFOUR_BYTE)&lastSector)->Byte3 = ((PFOUR_BYTE)&tmp)->Byte0;
+
+ //
+ // Calculate sector to byte shift.
+ //
+
+ WHICH_BIT(bps, deviceExtension->SectorShift);
+
+ DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Sector size is %d\n",
+ deviceExtension->DiskGeometry->BytesPerSector));
+
+ DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Number of Sectors is %d\n",
+ lastSector + 1));
+
+ //
+ // Calculate media capacity in bytes.
+ //
+
+ deviceExtension->PartitionLength.QuadPart = (LONGLONG)(lastSector + 1);
+
+ //
+ // Calculate number of cylinders.
+ //
+
+ deviceExtension->DiskGeometry->Cylinders.QuadPart = (LONGLONG)((lastSector + 1)/(32 * 64));
+
+ deviceExtension->PartitionLength.QuadPart =
+ (deviceExtension->PartitionLength.QuadPart << deviceExtension->SectorShift);
+
+ if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
+
+ //
+ // This device supports removable media.
+ //
+
+ deviceExtension->DiskGeometry->MediaType = RemovableMedia;
+
+ } else {
+
+ //
+ // Assume media type is fixed disk.
+ //
+
+ deviceExtension->DiskGeometry->MediaType = FixedMedia;
+ }
+
+ //
+ // Assume sectors per track are 32;
+ //
+
+ deviceExtension->DiskGeometry->SectorsPerTrack = 32;
+
+ //
+ // Assume tracks per cylinder (number of heads) is 64.
+ //
+
+ deviceExtension->DiskGeometry->TracksPerCylinder = 64;
+
+ //
+ // Copy the device extension's geometry info into the user buffer.
+ //
+
+ RtlMoveMemory(realIrp->AssociatedIrp.SystemBuffer,
+ deviceExtension->DiskGeometry,
+ sizeof(DISK_GEOMETRY));
+
+ //
+ // update information field.
+ //
+
+ realIrp->IoStatus.Information = sizeof(DISK_GEOMETRY);
+ break;
+ }
+
+ case IOCTL_CDROM_CHECK_VERIFY:
+
+ if((realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_CHECK_VERIFY) &&
+ (realIrpStack->Parameters.DeviceIoControl.OutputBufferLength)) {
+
+ *((PULONG)realIrp->AssociatedIrp.SystemBuffer) =
+ physicalExtension->MediaChangeCount;
+ realIrp->IoStatus.Information = sizeof(ULONG);
+ } else {
+ realIrp->IoStatus.Information = 0;
+ }
+
+ DebugPrint((2, "CdRomDeviceControlCompletion: [%lx] completing CHECK_VERIFY buddy irp %lx\n", realIrp, Irp));
+ break;
+
+ case IOCTL_CDROM_GET_LAST_SESSION:
+ case IOCTL_CDROM_READ_TOC: {
+
+ PCDROM_TOC toc = srb->DataBuffer;
+
+ //
+ // Copy the device extension's geometry info into the user buffer.
+ //
+
+ RtlMoveMemory(realIrp->AssociatedIrp.SystemBuffer,
+ toc,
+ srb->DataTransferLength);
+
+ //
+ // update information field.
+ //
+
+ realIrp->IoStatus.Information = srb->DataTransferLength;
+ break;
+ }
+
+ case IOCTL_CDROM_PLAY_AUDIO_MSF:
+
+ PLAY_ACTIVE(deviceExtension) = TRUE;
+
+ break;
+
+ case IOCTL_CDROM_READ_Q_CHANNEL: {
+
+ PSUB_Q_CHANNEL_DATA userChannelData = realIrp->AssociatedIrp.SystemBuffer;
+ PCDROM_SUB_Q_DATA_FORMAT inputBuffer = realIrp->AssociatedIrp.SystemBuffer;
+ PSUB_Q_CHANNEL_DATA subQPtr = srb->DataBuffer;
+
+#if DBG
+ switch( inputBuffer->Format ) {
+
+ case IOCTL_CDROM_CURRENT_POSITION:
+ DebugPrint((2,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr->CurrentPosition.Header.AudioStatus ));
+ DebugPrint((2,"CdRomDeviceControlCompletion: ADR = 0x%x\n", subQPtr->CurrentPosition.ADR ));
+ DebugPrint((2,"CdRomDeviceControlCompletion: Control = 0x%x\n", subQPtr->CurrentPosition.Control ));
+ DebugPrint((2,"CdRomDeviceControlCompletion: Track = %u\n", subQPtr->CurrentPosition.TrackNumber ));
+ DebugPrint((2,"CdRomDeviceControlCompletion: Index = %u\n", subQPtr->CurrentPosition.IndexNumber ));
+ DebugPrint((2,"CdRomDeviceControlCompletion: Absolute Address = %x\n", *((PULONG)subQPtr->CurrentPosition.AbsoluteAddress) ));
+ DebugPrint((2,"CdRomDeviceControlCompletion: Relative Address = %x\n", *((PULONG)subQPtr->CurrentPosition.TrackRelativeAddress) ));
+ break;
+
+ case IOCTL_CDROM_MEDIA_CATALOG:
+ DebugPrint((2,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr->MediaCatalog.Header.AudioStatus ));
+ DebugPrint((2,"CdRomDeviceControlCompletion: Mcval is %u\n", subQPtr->MediaCatalog.Mcval ));
+ break;
+
+ case IOCTL_CDROM_TRACK_ISRC:
+ DebugPrint((2,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr->TrackIsrc.Header.AudioStatus ));
+ DebugPrint((2,"CdRomDeviceControlCompletion: Tcval is %u\n", subQPtr->TrackIsrc.Tcval ));
+ break;
+
+ }
+#endif
+
+ //
+ // Update the play active status.
+ //
+
+ if (subQPtr->CurrentPosition.Header.AudioStatus == AUDIO_STATUS_IN_PROGRESS) {
+
+ PLAY_ACTIVE(deviceExtension) = TRUE;
+
+ } else {
+
+ PLAY_ACTIVE(deviceExtension) = FALSE;
+
+ }
+
+ //
+ // Check if output buffer is large enough to contain
+ // the data.
+ //
+
+ if (realIrpStack->Parameters.DeviceIoControl.OutputBufferLength <
+ srb->DataTransferLength) {
+
+ srb->DataTransferLength =
+ realIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
+ }
+
+ //
+ // Copy our buffer into users.
+ //
+
+ RtlMoveMemory(userChannelData,
+ subQPtr,
+ srb->DataTransferLength);
+
+ realIrp->IoStatus.Information = srb->DataTransferLength;
+ break;
+ }
+
+ case IOCTL_CDROM_PAUSE_AUDIO:
+
+ PLAY_ACTIVE(deviceExtension) = FALSE;
+ realIrp->IoStatus.Information = 0;
+ break;
+
+ case IOCTL_CDROM_RESUME_AUDIO:
+
+ realIrp->IoStatus.Information = 0;
+ break;
+
+ case IOCTL_CDROM_SEEK_AUDIO_MSF:
+
+ realIrp->IoStatus.Information = 0;
+ break;
+
+ case IOCTL_CDROM_STOP_AUDIO:
+
+ PLAY_ACTIVE(deviceExtension) = FALSE;
+
+ realIrp->IoStatus.Information = 0;
+ break;
+
+ case IOCTL_CDROM_GET_CONTROL: {
+
+ PCDROM_AUDIO_CONTROL audioControl = srb->DataBuffer;
+ PAUDIO_OUTPUT audioOutput;
+ ULONG bytesTransferred;
+
+ audioOutput = ScsiClassFindModePage((PCHAR)audioControl,
+ srb->DataTransferLength,
+ CDROM_AUDIO_CONTROL_PAGE,
+ use6Byte);
+ //
+ // Verify the page is as big as expected.
+ //
+
+ bytesTransferred = (PCHAR) audioOutput - (PCHAR) audioControl +
+ sizeof(AUDIO_OUTPUT);
+
+ if (audioOutput != NULL &&
+ srb->DataTransferLength >= bytesTransferred) {
+
+ audioControl->LbaFormat = audioOutput->LbaFormat;
+
+ audioControl->LogicalBlocksPerSecond =
+ (audioOutput->LogicalBlocksPerSecond[0] << (UCHAR)8) |
+ audioOutput->LogicalBlocksPerSecond[1];
+
+ realIrp->IoStatus.Information = sizeof(CDROM_AUDIO_CONTROL);
+
+ } else {
+ realIrp->IoStatus.Information = 0;
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ }
+ break;
+ }
+
+ case IOCTL_CDROM_GET_VOLUME: {
+
+ PAUDIO_OUTPUT audioOutput;
+ PVOLUME_CONTROL volumeControl = srb->DataBuffer;
+ ULONG i,bytesTransferred;
+
+ audioOutput = ScsiClassFindModePage((PCHAR)volumeControl,
+ srb->DataTransferLength,
+ CDROM_AUDIO_CONTROL_PAGE,
+ use6Byte);
+
+ //
+ // Verify the page is as big as expected.
+ //
+
+ bytesTransferred = (PCHAR) audioOutput - (PCHAR) volumeControl +
+ sizeof(AUDIO_OUTPUT);
+
+ if (audioOutput != NULL &&
+ srb->DataTransferLength >= bytesTransferred) {
+
+ for (i=0; i<4; i++) {
+ volumeControl->PortVolume[i] =
+ audioOutput->PortOutput[i].Volume;
+ }
+
+ //
+ // Set bytes transferred in IRP.
+ //
+
+ realIrp->IoStatus.Information = sizeof(VOLUME_CONTROL);
+
+ } else {
+ realIrp->IoStatus.Information = 0;
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ }
+
+ break;
+ }
+
+ case IOCTL_CDROM_SET_VOLUME:
+
+ realIrp->IoStatus.Information = sizeof(VOLUME_CONTROL);
+ break;
+
+ default:
+
+ ASSERT(FALSE);
+ realIrp->IoStatus.Information = 0;
+ status = STATUS_INVALID_DEVICE_REQUEST;
+
+ } // end switch()
+ }
+
+ //
+ // Deallocate srb and sense buffer.
+ //
+
+ if (srb) {
+ if (srb->DataBuffer) {
+ ExFreePool(srb->DataBuffer);
+ }
+ if (srb->SenseInfoBuffer) {
+ ExFreePool(srb->SenseInfoBuffer);
+ }
+ ExFreePool(srb);
+ }
+
+ if (realIrp->PendingReturned) {
+ IoMarkIrpPending(realIrp);
+ }
+
+ if (Irp->MdlAddress) {
+ IoFreeMdl(Irp->MdlAddress);
+ }
+
+ IoFreeIrp(Irp);
+
+ //
+ // Set status in completing IRP.
+ //
+
+ realIrp->IoStatus.Status = status;
+
+ //
+ // Set the hard error if necessary.
+ //
+
+ if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
+
+ //
+ // Store DeviceObject for filesystem, and clear
+ // in IoStatus.Information field.
+ //
+
+ DebugPrint((1, "CdRomDeviceCompletion - Setting Hard Error on realIrp %lx\n",
+ realIrp));
+ IoSetHardErrorOrVerifyDevice(realIrp, DeviceObject);
+ realIrp->IoStatus.Information = 0;
+ }
+
+ IoCompleteRequest(realIrp, IO_DISK_INCREMENT);
+
+ IoStartNextPacket(DeviceObject, FALSE);
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+\f
+NTSTATUS
+STDCALL
+CdRomSetVolumeIntermediateCompletion(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+{
+ PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
+ PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
+ PCDROM_DATA cdData = (PCDROM_DATA)(deviceExtension + 1);
+ BOOLEAN use6Byte = cdData->XAFlags & XA_USE_6_BYTE;
+ PIO_STACK_LOCATION realIrpStack;
+ PIO_STACK_LOCATION realIrpNextStack;
+ PSCSI_REQUEST_BLOCK srb = Context;
+ PIRP realIrp = NULL;
+ NTSTATUS status;
+ BOOLEAN retry;
+
+ //
+ // Extract the 'real' irp from the irpstack.
+ //
+
+ realIrp = (PIRP) irpStack->Parameters.Others.Argument2;
+ realIrpStack = IoGetCurrentIrpStackLocation(realIrp);
+ realIrpNextStack = IoGetNextIrpStackLocation(realIrp);
+
+ //
+ // Check SRB status for success of completing request.
+ //
+
+ if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
+
+ DebugPrint((2,
+ "CdRomSetVolumeIntermediateCompletion: Irp %lx, Srb %lx Real Irp\n",
+ Irp,
+ srb,
+ realIrp));
+
+ //
+ // Release the queue if it is frozen.
+ //
+
+ if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
+ ScsiClassReleaseQueue(DeviceObject);
+ }
+
+
+ retry = ScsiClassInterpretSenseInfo(DeviceObject,
+ srb,
+ irpStack->MajorFunction,
+ irpStack->Parameters.DeviceIoControl.IoControlCode,
+ MAXIMUM_RETRIES - ((ULONG)realIrpNextStack->Parameters.Others.Argument1),
+ &status);
+
+ if (status == STATUS_DATA_OVERRUN) {
+ status = STATUS_SUCCESS;
+ retry = FALSE;
+ }
+
+ //
+ // If the status is verified required and the this request
+ // should bypass verify required then retry the request.
+ //
+
+ if (realIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
+ status == STATUS_VERIFY_REQUIRED) {
+
+ status = STATUS_IO_DEVICE_ERROR;
+ retry = TRUE;
+ }
+
+ if (retry && (realIrpNextStack->Parameters.Others.Argument1 = (ULONG)realIrpNextStack->Parameters.Others.Argument1-1)) {
+
+ if (((ULONG)realIrpNextStack->Parameters.Others.Argument1)) {
+
+ //
+ // Retry request.
+ //
+
+ DebugPrint((1, "Retry request %lx - Calling StartIo\n", Irp));
+
+
+ ExFreePool(srb->SenseInfoBuffer);
+ ExFreePool(srb->DataBuffer);
+ ExFreePool(srb);
+ if (Irp->MdlAddress) {
+ IoFreeMdl(Irp->MdlAddress);
+ }
+
+ IoFreeIrp(Irp);
+
+ //
+ // Call StartIo directly since IoStartNextPacket hasn't been called,
+ // the serialisation is still intact.
+ //
+ ScsiCdRomStartIo(DeviceObject, realIrp);
+ return STATUS_MORE_PROCESSING_REQUIRED;
+
+ }
+
+ //
+ // Exhausted retries. Fall through and complete the request with the appropriate status.
+ //
+
+ }
+ } else {
+
+ //
+ // Set status for successful request.
+ //
+
+ status = STATUS_SUCCESS;
+ }
+
+ if (NT_SUCCESS(status)) {
+
+ PAUDIO_OUTPUT audioInput = NULL;
+ PAUDIO_OUTPUT audioOutput;
+ PVOLUME_CONTROL volumeControl = realIrp->AssociatedIrp.SystemBuffer;
+ ULONG i,bytesTransferred,headerLength;
+ PVOID dataBuffer;
+ PCDB cdb;
+
+ audioInput = ScsiClassFindModePage((PCHAR)srb->DataBuffer,
+ srb->DataTransferLength,
+ CDROM_AUDIO_CONTROL_PAGE,
+ use6Byte);
+
+ //
+ // Check to make sure the mode sense data is valid before we go on
+ //
+
+ if(audioInput == NULL) {
+
+ DebugPrint((1, "Mode Sense Page %d not found\n",
+ CDROM_AUDIO_CONTROL_PAGE));
+
+ realIrp->IoStatus.Information = 0;
+ realIrp->IoStatus.Status = STATUS_IO_DEVICE_ERROR;
+ IoCompleteRequest(realIrp, IO_DISK_INCREMENT);
+ ExFreePool(srb->SenseInfoBuffer);
+ ExFreePool(srb);
+ IoFreeMdl(Irp->MdlAddress);
+ IoFreeIrp(Irp);
+ return STATUS_MORE_PROCESSING_REQUIRED;
+ }
+
+ if (use6Byte) {
+ headerLength = sizeof(MODE_PARAMETER_HEADER);
+ } else {
+ headerLength = sizeof(MODE_PARAMETER_HEADER10);
+ }
+
+ bytesTransferred = sizeof(AUDIO_OUTPUT) + headerLength;
+
+ //
+ // Allocate a new buffer for the mode select.
+ //
+
+ dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, bytesTransferred);
+
+ if (!dataBuffer) {
+ realIrp->IoStatus.Information = 0;
+ realIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest(realIrp, IO_DISK_INCREMENT);
+ ExFreePool(srb->SenseInfoBuffer);
+ ExFreePool(srb);
+ IoFreeMdl(Irp->MdlAddress);
+ IoFreeIrp(Irp);
+ return STATUS_MORE_PROCESSING_REQUIRED;
+ }
+
+ RtlZeroMemory(dataBuffer, bytesTransferred);
+
+ //
+ // Rebuild the data buffer to include the user requested values.
+ //
+
+ audioOutput = (PAUDIO_OUTPUT) ((PCHAR) dataBuffer + headerLength);
+
+ for (i=0; i<4; i++) {
+ audioOutput->PortOutput[i].Volume =
+ volumeControl->PortVolume[i];
+ audioOutput->PortOutput[i].ChannelSelection =
+ audioInput->PortOutput[i].ChannelSelection;
+ }
+
+ audioOutput->CodePage = CDROM_AUDIO_CONTROL_PAGE;
+ audioOutput->ParameterLength = sizeof(AUDIO_OUTPUT) - 2;
+ audioOutput->Immediate = MODE_SELECT_IMMEDIATE;
+
+ //
+ // Free the old data buffer, mdl.
+ //
+
+ ExFreePool(srb->DataBuffer);
+ IoFreeMdl(Irp->MdlAddress);
+
+ //
+ // rebuild the srb.
+ //
+
+ cdb = (PCDB)srb->Cdb;
+ RtlZeroMemory(cdb, CDB12GENERIC_LENGTH);
+
+ srb->SrbStatus = srb->ScsiStatus = 0;
+ srb->SrbFlags = deviceExtension->SrbFlags;
+ srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_OUT);
+ srb->DataTransferLength = bytesTransferred;
+
+ if (use6Byte) {
+
+ cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
+ cdb->MODE_SELECT.ParameterListLength = (UCHAR) bytesTransferred;
+ cdb->MODE_SELECT.PFBit = 1;
+ srb->CdbLength = 6;
+ } else {
+
+ cdb->MODE_SELECT10.OperationCode = SCSIOP_MODE_SELECT10;
+ cdb->MODE_SELECT10.ParameterListLength[0] = (UCHAR) (bytesTransferred >> 8);
+ cdb->MODE_SELECT10.ParameterListLength[1] = (UCHAR) (bytesTransferred & 0xFF);
+ cdb->MODE_SELECT10.PFBit = 1;
+ srb->CdbLength = 10;
+ }
+
+ //
+ // Prepare the MDL
+ //
+
+ Irp->MdlAddress = IoAllocateMdl(dataBuffer,
+ bytesTransferred,
+ FALSE,
+ FALSE,
+ (PIRP) NULL);
+
+ if (!Irp->MdlAddress) {
+ realIrp->IoStatus.Information = 0;
+ realIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest(realIrp, IO_DISK_INCREMENT);
+ ExFreePool(srb->SenseInfoBuffer);
+ ExFreePool(srb);
+ ExFreePool(dataBuffer);
+ IoFreeIrp(Irp);
+ return STATUS_MORE_PROCESSING_REQUIRED;
+
+ }
+
+ MmBuildMdlForNonPagedPool(Irp->MdlAddress);
+ srb->DataBuffer = dataBuffer;
+
+ irpStack = IoGetNextIrpStackLocation(Irp);
+ irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
+ irpStack->Parameters.Scsi.Srb = srb;
+
+ //
+ // reset the irp completion.
+ //
+
+ IoSetCompletionRoutine(Irp,
+ CdRomDeviceControlCompletion,
+ srb,
+ TRUE,
+ TRUE,
+ TRUE);
+ //
+ // Call the port driver.
+ //
+
+ IoCallDriver(deviceExtension->PortDeviceObject, Irp);
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+ }
+
+ //
+ // Deallocate srb and sense buffer.
+ //
+
+ if (srb) {
+ if (srb->DataBuffer) {
+ ExFreePool(srb->DataBuffer);
+ }
+ if (srb->SenseInfoBuffer) {
+ ExFreePool(srb->SenseInfoBuffer);
+ }
+ ExFreePool(srb);
+ }
+
+ if (Irp->PendingReturned) {
+ IoMarkIrpPending(Irp);
+ }
+
+ if (realIrp->PendingReturned) {
+ IoMarkIrpPending(realIrp);
+ }
+
+ if (Irp->MdlAddress) {
+ IoFreeMdl(Irp->MdlAddress);
+ }
+
+ IoFreeIrp(Irp);
+
+ //
+ // Set status in completing IRP.
+ //
+
+ realIrp->IoStatus.Status = status;
+
+ //
+ // Set the hard error if necessary.
+ //
+
+ if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
+
+ //
+ // Store DeviceObject for filesystem, and clear
+ // in IoStatus.Information field.
+ //
+
+ IoSetHardErrorOrVerifyDevice(realIrp, DeviceObject);
+ realIrp->IoStatus.Information = 0;
+ }
+
+ IoCompleteRequest(realIrp, IO_DISK_INCREMENT);
+
+ IoStartNextPacket(DeviceObject, FALSE);
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+
+\f
+NTSTATUS
+STDCALL
+CdRomSwitchModeCompletion(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+{
+ PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
+ PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
+ PCDROM_DATA cdData = (PCDROM_DATA)(deviceExtension + 1);
+ BOOLEAN use6Byte = cdData->XAFlags & XA_USE_6_BYTE;
+ PIO_STACK_LOCATION realIrpStack;
+ PIO_STACK_LOCATION realIrpNextStack;
+ PSCSI_REQUEST_BLOCK srb = Context;
+ PIRP realIrp = NULL;
+ NTSTATUS status;
+ BOOLEAN retry;
+
+ //
+ // Extract the 'real' irp from the irpstack.
+ //
+
+ realIrp = (PIRP) irpStack->Parameters.Others.Argument2;
+ realIrpStack = IoGetCurrentIrpStackLocation(realIrp);
+ realIrpNextStack = IoGetNextIrpStackLocation(realIrp);
+
+ //
+ // Check SRB status for success of completing request.
+ //
+
+ if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
+
+ DebugPrint((2,
+ "CdRomSetVolumeIntermediateCompletion: Irp %lx, Srb %lx Real Irp\n",
+ Irp,
+ srb,
+ realIrp));
+
+ //
+ // Release the queue if it is frozen.
+ //
+
+ if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
+ ScsiClassReleaseQueue(DeviceObject);
+ }
+
+
+ retry = ScsiClassInterpretSenseInfo(DeviceObject,
+ srb,
+ irpStack->MajorFunction,
+ irpStack->Parameters.DeviceIoControl.IoControlCode,
+ MAXIMUM_RETRIES - ((ULONG)realIrpNextStack->Parameters.Others.Argument1),
+ &status);
+
+ //
+ // If the status is verified required and the this request
+ // should bypass verify required then retry the request.
+ //
+
+ if (realIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
+ status == STATUS_VERIFY_REQUIRED) {
+
+ status = STATUS_IO_DEVICE_ERROR;
+ retry = TRUE;
+ }
+
+ if (retry && (realIrpNextStack->Parameters.Others.Argument1 = (ULONG)realIrpNextStack->Parameters.Others.Argument1-1)) {
+
+ if (((ULONG)realIrpNextStack->Parameters.Others.Argument1)) {
+
+ //
+ // Retry request.
+ //
+
+ DebugPrint((1, "Retry request %lx - Calling StartIo\n", Irp));
+
+
+ ExFreePool(srb->SenseInfoBuffer);
+ ExFreePool(srb->DataBuffer);
+ ExFreePool(srb);
+ if (Irp->MdlAddress) {
+ IoFreeMdl(Irp->MdlAddress);
+ }
+
+ IoFreeIrp(Irp);
+
+ //
+ // Call StartIo directly since IoStartNextPacket hasn't been called,
+ // the serialisation is still intact.
+ //
+
+ ScsiCdRomStartIo(DeviceObject, realIrp);
+ return STATUS_MORE_PROCESSING_REQUIRED;
+
+ }
+
+ //
+ // Exhausted retries. Fall through and complete the request with the appropriate status.
+ //
+ }
+ } else {
+
+ //
+ // Set status for successful request.
+ //
+
+ status = STATUS_SUCCESS;
+ }
+
+ if (NT_SUCCESS(status)) {
+
+ ULONG sectorSize, startingSector, transferByteCount;
+ PCDB cdb;
+
+ //
+ // Update device ext. to show which mode we are currently using.
+ //
+
+ sectorSize = cdData->u1.BlockDescriptor.BlockLength[0] << 16;
+ sectorSize |= (cdData->u1.BlockDescriptor.BlockLength[1] << 8);
+ sectorSize |= (cdData->u1.BlockDescriptor.BlockLength[2]);
+
+ cdData->RawAccess = (sectorSize == RAW_SECTOR_SIZE) ? TRUE : FALSE;
+
+ //
+ // Free the old data buffer, mdl.
+ //
+
+ ExFreePool(srb->DataBuffer);
+ IoFreeMdl(Irp->MdlAddress);
+ IoFreeIrp(Irp);
+
+ //
+ // rebuild the srb.
+ //
+
+ cdb = (PCDB)srb->Cdb;
+ RtlZeroMemory(cdb, CDB12GENERIC_LENGTH);
+
+
+ if (cdData->RawAccess) {
+
+ PRAW_READ_INFO rawReadInfo =
+ (PRAW_READ_INFO)realIrpStack->Parameters.DeviceIoControl.Type3InputBuffer;
+
+ ULONG maximumTransferLength;
+ ULONG transferPages;
+ UCHAR min, sec, frame;
+
+ //
+ // Calculate starting offset.
+ //
+
+ startingSector = (ULONG)(rawReadInfo->DiskOffset.QuadPart >> deviceExtension->SectorShift);
+ transferByteCount = rawReadInfo->SectorCount * RAW_SECTOR_SIZE;
+ maximumTransferLength = deviceExtension->PortCapabilities->MaximumTransferLength;
+ transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(realIrp->MdlAddress),
+ transferByteCount);
+
+ //
+ // Determine if request is within limits imposed by miniport.
+ // If the request is larger than the miniport's capabilities, split it.
+ //
+
+ if (transferByteCount > maximumTransferLength ||
+ transferPages > deviceExtension->PortCapabilities->MaximumPhysicalPages) {
+
+ realIrp->IoStatus.Information = 0;
+ realIrp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ IoCompleteRequest(realIrp, IO_DISK_INCREMENT);
+
+ ExFreePool(srb->SenseInfoBuffer);
+ ExFreePool(srb->DataBuffer);
+ ExFreePool(srb);
+ IoFreeMdl(Irp->MdlAddress);
+ IoFreeIrp(Irp);
+
+ IoStartNextPacket(DeviceObject, FALSE);
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+ }
+
+ srb->OriginalRequest = realIrp;
+ srb->SrbFlags = deviceExtension->SrbFlags;
+ srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
+ srb->DataTransferLength = transferByteCount;
+ srb->TimeOutValue = deviceExtension->TimeOutValue;
+ srb->CdbLength = 10;
+ srb->DataBuffer = MmGetMdlVirtualAddress(realIrp->MdlAddress);
+
+ if (rawReadInfo->TrackMode == CDDA) {
+ if (cdData->XAFlags & PLEXTOR_CDDA) {
+
+ srb->CdbLength = 12;
+
+ cdb->PLXTR_READ_CDDA.LogicalUnitNumber = deviceExtension->Lun;
+ cdb->PLXTR_READ_CDDA.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
+ cdb->PLXTR_READ_CDDA.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
+ cdb->PLXTR_READ_CDDA.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
+ cdb->PLXTR_READ_CDDA.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
+
+ cdb->PLXTR_READ_CDDA.TransferBlockByte3 = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
+ cdb->PLXTR_READ_CDDA.TransferBlockByte2 = (UCHAR) (rawReadInfo->SectorCount >> 8);
+ cdb->PLXTR_READ_CDDA.TransferBlockByte1 = 0;
+ cdb->PLXTR_READ_CDDA.TransferBlockByte0 = 0;
+
+ cdb->PLXTR_READ_CDDA.SubCode = 0;
+ cdb->PLXTR_READ_CDDA.OperationCode = 0xD8;
+
+ } else if (cdData->XAFlags & NEC_CDDA) {
+
+ cdb->NEC_READ_CDDA.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
+ cdb->NEC_READ_CDDA.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
+ cdb->NEC_READ_CDDA.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
+ cdb->NEC_READ_CDDA.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
+
+ cdb->NEC_READ_CDDA.TransferBlockByte1 = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
+ cdb->NEC_READ_CDDA.TransferBlockByte0 = (UCHAR) (rawReadInfo->SectorCount >> 8);
+
+ cdb->NEC_READ_CDDA.OperationCode = 0xD4;
+ }
+ } else {
+ cdb->CDB10.LogicalUnitNumber = deviceExtension->Lun;
+
+ cdb->CDB10.TransferBlocksMsb = (UCHAR) (rawReadInfo->SectorCount >> 8);
+ cdb->CDB10.TransferBlocksLsb = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
+
+ cdb->CDB10.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
+ cdb->CDB10.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
+ cdb->CDB10.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
+ cdb->CDB10.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
+
+ cdb->CDB10.OperationCode = SCSIOP_READ;
+ }
+
+ srb->SrbStatus = srb->ScsiStatus = 0;
+
+
+ irpStack = IoGetNextIrpStackLocation(realIrp);
+ irpStack->MajorFunction = IRP_MJ_SCSI;
+ irpStack->Parameters.Scsi.Srb = srb;
+
+ if (!(irpStack->Parameters.Others.Argument1)) {
+
+ //
+ // Only jam this in if it doesn't exist. The completion routines can
+ // call StartIo directly in the case of retries and resetting it will
+ // cause infinite loops.
+ //
+
+ irpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
+ }
+
+ //
+ // Set up IoCompletion routine address.
+ //
+
+ IoSetCompletionRoutine(realIrp,
+ CdRomXACompletion,
+ srb,
+ TRUE,
+ TRUE,
+ TRUE);
+ } else {
+
+ ULONG maximumTransferLength = deviceExtension->PortCapabilities->MaximumTransferLength;
+ ULONG transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(realIrp->MdlAddress),
+ realIrpStack->Parameters.Read.Length);
+ //
+ // Back to cooked sectors. Build and send a normal read.
+ // The real work for setting offsets and checking for splitrequests was
+ // done in startio
+ //
+
+ if ((realIrpStack->Parameters.Read.Length > maximumTransferLength) ||
+ (transferPages > deviceExtension->PortCapabilities->MaximumPhysicalPages)) {
+
+ //
+ // Request needs to be split. Completion of each portion of the request will
+ // fire off the next portion. The final request will signal Io to send a new request.
+ //
+
+ ScsiClassSplitRequest(DeviceObject, realIrp, maximumTransferLength);
+ return STATUS_MORE_PROCESSING_REQUIRED;
+
+ } else {
+
+ //
+ // Build SRB and CDB for this IRP.
+ //
+
+ ScsiClassBuildRequest(DeviceObject, realIrp);
+
+ }
+ }
+
+ //
+ // Call the port driver.
+ //
+
+ IoCallDriver(deviceExtension->PortDeviceObject, realIrp);
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+ }
+
+ //
+ // Update device Extension flags to indicate that XA isn't supported.
+ //
+
+ cdData->XAFlags |= XA_NOT_SUPPORTED;
+
+ //
+ // Deallocate srb and sense buffer.
+ //
+
+ if (srb) {
+ if (srb->DataBuffer) {
+ ExFreePool(srb->DataBuffer);
+ }
+ if (srb->SenseInfoBuffer) {
+ ExFreePool(srb->SenseInfoBuffer);
+ }
+ ExFreePool(srb);
+ }
+
+ if (Irp->PendingReturned) {
+ IoMarkIrpPending(Irp);
+ }
+
+ if (realIrp->PendingReturned) {
+ IoMarkIrpPending(realIrp);
+ }
+
+ if (Irp->MdlAddress) {
+ IoFreeMdl(Irp->MdlAddress);
+ }
+
+ IoFreeIrp(Irp);
+
+ //
+ // Set status in completing IRP.
+ //
+
+ realIrp->IoStatus.Status = status;
+
+ //
+ // Set the hard error if necessary.
+ //
+
+ if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
+
+ //
+ // Store DeviceObject for filesystem, and clear
+ // in IoStatus.Information field.
+ //
+
+ IoSetHardErrorOrVerifyDevice(realIrp, DeviceObject);
+ realIrp->IoStatus.Information = 0;
+ }
+
+ IoCompleteRequest(realIrp, IO_DISK_INCREMENT);
+
+ IoStartNextPacket(DeviceObject, FALSE);
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+\f
+NTSTATUS
+STDCALL
+CdRomXACompletion(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine executes when the port driver has completed a request.
+ It looks at the SRB status in the completing SRB and if not success
+ it checks for valid request sense buffer information. If valid, the
+ info is used to update status with more precise message of type of
+ error. This routine deallocates the SRB.
+
+Arguments:
+
+ DeviceObject - Supplies the device object which represents the logical
+ unit.
+
+ Irp - Supplies the Irp which has completed.
+
+ Context - Supplies a pointer to the SRB.
+
+Return Value:
+
+ NT status
+
+--*/
+
+{
+ PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
+ PIO_STACK_LOCATION irpNextStack = IoGetNextIrpStackLocation(Irp);
+ PSCSI_REQUEST_BLOCK srb = Context;
+ PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
+ NTSTATUS status;
+ BOOLEAN retry;
+
+ //
+ // Check SRB status for success of completing request.
+ //
+
+ if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
+
+ DebugPrint((2,"ScsiClassIoComplete: IRP %lx, SRB %lx\n", Irp, srb));
+
+ //
+ // Release the queue if it is frozen.
+ //
+
+ if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
+ ScsiClassReleaseQueue(DeviceObject);
+ }
+
+ retry = ScsiClassInterpretSenseInfo(
+ DeviceObject,
+ srb,
+ irpStack->MajorFunction,
+ irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL ? irpStack->Parameters.DeviceIoControl.IoControlCode : 0,
+ MAXIMUM_RETRIES - ((ULONG)irpNextStack->Parameters.Others.Argument1),
+ &status);
+
+ //
+ // If the status is verified required and the this request
+ // should bypass verify required then retry the request.
+ //
+
+ if (irpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
+ status == STATUS_VERIFY_REQUIRED) {
+
+ status = STATUS_IO_DEVICE_ERROR;
+ retry = TRUE;
+ }
+
+ if (retry && (irpNextStack->Parameters.Others.Argument1 = (ULONG)irpNextStack->Parameters.Others.Argument1-1)) {
+
+ if (((ULONG)irpNextStack->Parameters.Others.Argument1)) {
+
+ //
+ // Retry request.
+ //
+
+ DebugPrint((1, "CdRomXACompletion: Retry request %lx - Calling StartIo\n", Irp));
+
+
+ ExFreePool(srb->SenseInfoBuffer);
+ ExFreePool(srb->DataBuffer);
+ ExFreePool(srb);
+
+ //
+ // Call StartIo directly since IoStartNextPacket hasn't been called,
+ // the serialisation is still intact.
+ //
+
+ ScsiCdRomStartIo(DeviceObject, Irp);
+ return STATUS_MORE_PROCESSING_REQUIRED;
+
+ }
+
+ //
+ // Exhausted retries. Fall through and complete the request with the appropriate status.
+ //
+ }
+ } else {
+
+ //
+ // Set status for successful request.
+ //
+
+ status = STATUS_SUCCESS;
+
+ } // end if (SRB_STATUS(srb->SrbStatus) ...
+
+ //
+ // Return SRB to nonpaged pool.
+ //
+
+ ExFreePool(srb);
+
+ //
+ // Set status in completing IRP.
+ //
+
+ Irp->IoStatus.Status = status;
+
+ //
+ // Set the hard error if necessary.
+ //
+
+ if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
+
+ //
+ // Store DeviceObject for filesystem, and clear
+ // in IoStatus.Information field.
+ //
+
+ IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
+ Irp->IoStatus.Information = 0;
+ }
+
+ //
+ // If pending has be returned for this irp then mark the current stack as
+ // pending.
+ //
+
+ if (Irp->PendingReturned) {
+ IoMarkIrpPending(Irp);
+ }
+
+ //IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+ IoStartNextPacket(DeviceObject, FALSE);
+
+ return status;
+}
+
+\f
+NTSTATUS
+STDCALL
+CdRomDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This is the NT device control handler for CDROMs.
+
+Arguments:
+
+ DeviceObject - for this CDROM
+
+ Irp - IO Request packet
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+
+{
+ PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
+ PIO_STACK_LOCATION nextStack;
+ PKEVENT deviceControlEvent;
+ PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
+ PCDROM_DATA cdData = (PCDROM_DATA)(deviceExtension+1);
+ BOOLEAN use6Byte = cdData->XAFlags & XA_USE_6_BYTE;
+ SCSI_REQUEST_BLOCK srb;
+ PCDB cdb = (PCDB)srb.Cdb;
+ PVOID outputBuffer;
+ ULONG bytesTransferred = 0;
+ NTSTATUS status;
+ NTSTATUS status2;
+ KIRQL irql;
+
+ ULONG ioctlCode;
+ ULONG baseCode;
+ ULONG functionCode;
+
+RetryControl:
+
+ //
+ // Zero the SRB on stack.
+ //
+
+ RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
+
+ Irp->IoStatus.Information = 0;
+
+ //
+ // if this is a class driver ioctl then we need to change the base code
+ // to IOCTL_CDROM_BASE so that the switch statement can handle it.
+ //
+ // WARNING - currently the scsi class ioctl function codes are between
+ // 0x200 & 0x300. this routine depends on that fact
+ //
+
+ ioctlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
+ baseCode = ioctlCode >> 16;
+ functionCode = (ioctlCode & (~0xffffc003)) >> 2;
+
+ DebugPrint((1, "CdRomDeviceControl: Ioctl Code = %#08lx, Base Code = %#lx,"
+ " Function Code = %#lx\n",
+ ioctlCode,
+ baseCode,
+ functionCode
+ ));
+
+ if((functionCode >= 0x200) && (functionCode <= 0x300)) {
+
+ ioctlCode = (ioctlCode & 0x0000ffff) | CTL_CODE(IOCTL_CDROM_BASE, 0, 0, 0);
+
+ DebugPrint((1, "CdRomDeviceControl: Class Code - new ioctl code is %#08lx\n",
+ ioctlCode));
+
+ irpStack->Parameters.DeviceIoControl.IoControlCode = ioctlCode;
+
+ }
+
+ switch (ioctlCode) {
+
+ case IOCTL_CDROM_RAW_READ: {
+
+ LARGE_INTEGER startingOffset;
+ ULONG transferBytes;
+ ULONG startingSector;
+ PRAW_READ_INFO rawReadInfo = (PRAW_READ_INFO)irpStack->Parameters.DeviceIoControl.Type3InputBuffer;
+ PUCHAR userData = (PUCHAR)Irp->AssociatedIrp.SystemBuffer;
+
+ //
+ // Ensure that XA reads are supported.
+ //
+
+ if (cdData->XAFlags & XA_NOT_SUPPORTED) {
+
+ DebugPrint((1,
+ "CdRomDeviceControl: XA Reads not supported. Flags (%x)\n",
+ cdData->XAFlags));
+
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+ }
+
+ //
+ // Check that ending sector is on disc and buffers are there and of
+ // correct size.
+ //
+
+ if (rawReadInfo == NULL) {
+
+ //
+ // Called from user space. Validate the buffers.
+ //
+
+ rawReadInfo = (PRAW_READ_INFO)userData;
+ irpStack->Parameters.DeviceIoControl.Type3InputBuffer = (PVOID)userData;
+
+ if (rawReadInfo == NULL) {
+
+ DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (No extent info\n"));
+
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (irpStack->Parameters.DeviceIoControl.InputBufferLength != sizeof(RAW_READ_INFO)) {
+
+ DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (Invalid info buffer\n"));
+
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ startingOffset.QuadPart = rawReadInfo->DiskOffset.QuadPart;
+ startingSector = (ULONG)(rawReadInfo->DiskOffset.QuadPart >> deviceExtension->SectorShift);
+ transferBytes = rawReadInfo->SectorCount * RAW_SECTOR_SIZE;
+
+ if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < transferBytes) {
+
+ DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (Bad buffer size)\n"));
+
+ //
+ // Fail request with status of invalid parameters.
+ //
+
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if ((startingOffset.QuadPart + transferBytes) > deviceExtension->PartitionLength.QuadPart) {
+
+ DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (Request Out of Bounds)\n"));
+
+ //
+ // Fail request with status of invalid parameters.
+ //
+
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ IoMarkIrpPending(Irp);
+ IoStartPacket(DeviceObject, Irp, NULL, NULL);
+
+ return STATUS_PENDING;
+ }
+
+ case IOCTL_CDROM_GET_DRIVE_GEOMETRY: {
+
+ DebugPrint((2,"CdRomDeviceControl: Get drive geometry\n"));
+
+ if ( irpStack->Parameters.DeviceIoControl.OutputBufferLength <
+ sizeof( DISK_GEOMETRY ) ) {
+
+ status = STATUS_INFO_LENGTH_MISMATCH;
+ break;
+ }
+
+ IoMarkIrpPending(Irp);
+ IoStartPacket(DeviceObject,Irp, NULL,NULL);
+
+ return STATUS_PENDING;
+ }
+
+ case IOCTL_CDROM_GET_LAST_SESSION:
+ case IOCTL_CDROM_READ_TOC: {
+
+ //
+ // If the cd is playing music then reject this request.
+ //
+
+ if (CdRomIsPlayActive(DeviceObject)) {
+ Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_DEVICE_BUSY;
+ }
+
+ IoMarkIrpPending(Irp);
+ IoStartPacket(DeviceObject, Irp, NULL, NULL);
+
+ return STATUS_PENDING;
+ }
+
+ case IOCTL_CDROM_PLAY_AUDIO_MSF: {
+
+ //
+ // Play Audio MSF
+ //
+
+ DebugPrint((2,"CdRomDeviceControl: Play audio MSF\n"));
+
+ if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
+ sizeof(CDROM_PLAY_AUDIO_MSF)) {
+
+ //
+ // Indicate unsuccessful status.
+ //
+
+ status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+
+ IoMarkIrpPending(Irp);
+ IoStartPacket(DeviceObject, Irp, NULL, NULL);
+
+ return STATUS_PENDING;
+ }
+
+ case IOCTL_CDROM_SEEK_AUDIO_MSF: {
+
+
+ //
+ // Seek Audio MSF
+ //
+
+ DebugPrint((2,"CdRomDeviceControl: Seek audio MSF\n"));
+
+ if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
+ sizeof(CDROM_SEEK_AUDIO_MSF)) {
+
+ //
+ // Indicate unsuccessful status.
+ //
+
+ status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ } else {
+ IoMarkIrpPending(Irp);
+ IoStartPacket(DeviceObject, Irp, NULL, NULL);
+
+ return STATUS_PENDING;
+
+ }
+ }
+
+ case IOCTL_CDROM_PAUSE_AUDIO: {
+
+ //
+ // Pause audio
+ //
+
+ DebugPrint((2, "CdRomDeviceControl: Pause audio\n"));
+
+ IoMarkIrpPending(Irp);
+ IoStartPacket(DeviceObject, Irp, NULL, NULL);
+
+ return STATUS_PENDING;
+
+ break;
+ }
+
+ case IOCTL_CDROM_RESUME_AUDIO: {
+
+ //
+ // Resume audio
+ //
+
+ DebugPrint((2, "CdRomDeviceControl: Resume audio\n"));
+
+ IoMarkIrpPending(Irp);
+ IoStartPacket(DeviceObject, Irp, NULL, NULL);
+
+ return STATUS_PENDING;
+ }
+
+ case IOCTL_CDROM_READ_Q_CHANNEL: {
+
+ if(irpStack->Parameters.DeviceIoControl.InputBufferLength <
+ sizeof(CDROM_SUB_Q_DATA_FORMAT)) {
+
+ status = STATUS_BUFFER_TOO_SMALL;
+ Irp->IoStatus.Information = 0;
+ break;
+ }
+
+ IoMarkIrpPending(Irp);
+ IoStartPacket(DeviceObject, Irp, NULL, NULL);
+
+ return STATUS_PENDING;
+ }
+
+ case IOCTL_CDROM_GET_CONTROL: {
+
+ DebugPrint((2, "CdRomDeviceControl: Get audio control\n"));
+
+ //
+ // Verify user buffer is large enough for the data.
+ //
+
+ if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
+ sizeof(CDROM_AUDIO_CONTROL)) {
+
+ //
+ // Indicate unsuccessful status and no data transferred.
+ //
+
+ status = STATUS_BUFFER_TOO_SMALL;
+ Irp->IoStatus.Information = 0;
+ break;
+
+ } else {
+
+ IoMarkIrpPending(Irp);
+ IoStartPacket(DeviceObject, Irp, NULL, NULL);
+
+ return STATUS_PENDING;
+ }
+ }
+
+ case IOCTL_CDROM_GET_VOLUME: {
+
+ DebugPrint((2, "CdRomDeviceControl: Get volume control\n"));
+
+ //
+ // Verify user buffer is large enough for data.
+ //
+
+ if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
+ sizeof(VOLUME_CONTROL)) {
+
+ //
+ // Indicate unsuccessful status and no data transferred.
+ //
+
+ status = STATUS_BUFFER_TOO_SMALL;
+ Irp->IoStatus.Information = 0;
+ break;
+
+ } else {
+ IoMarkIrpPending(Irp);
+ IoStartPacket(DeviceObject, Irp, NULL, NULL);
+
+ return STATUS_PENDING;
+ }
+ }
+
+ case IOCTL_CDROM_SET_VOLUME: {
+
+ DebugPrint((2, "CdRomDeviceControl: Set volume control\n"));
+
+ if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
+ sizeof(VOLUME_CONTROL)) {
+
+ //
+ // Indicate unsuccessful status.
+ //
+
+ status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ } else {
+
+ IoMarkIrpPending(Irp);
+ IoStartPacket(DeviceObject, Irp, NULL, NULL);
+
+ return STATUS_PENDING;
+ }
+ }
+
+ case IOCTL_CDROM_STOP_AUDIO: {
+
+ //
+ // Stop play.
+ //
+
+ DebugPrint((2, "CdRomDeviceControl: Stop audio\n"));
+
+ IoMarkIrpPending(Irp);
+ IoStartPacket(DeviceObject,Irp, NULL,NULL);
+
+ return STATUS_PENDING;
+ }
+
+ case IOCTL_CDROM_CHECK_VERIFY: {
+ DebugPrint((1, "CdRomDeviceControl: [%lx] Check Verify\n", Irp));
+ IoMarkIrpPending(Irp);
+
+ if((irpStack->Parameters.DeviceIoControl.OutputBufferLength) &&
+ (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG))) {
+
+ DebugPrint((1, "CdRomDeviceControl: Check Verify: media count "
+ "buffer too small\n"));
+
+ status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+
+ IoStartPacket(DeviceObject,Irp, NULL,NULL);
+
+ return STATUS_PENDING;
+ }
+
+ default: {
+
+ //
+ // allocate an event and stuff it into our stack location.
+ //
+
+ deviceControlEvent = ExAllocatePool(NonPagedPool, sizeof(KEVENT));
+
+ if(!deviceControlEvent) {
+
+ status = STATUS_INSUFFICIENT_RESOURCES;
+
+ } else {
+
+ PIO_STACK_LOCATION currentStack;
+
+ KeInitializeEvent(deviceControlEvent, NotificationEvent, FALSE);
+
+ currentStack = IoGetCurrentIrpStackLocation(Irp);
+ nextStack = IoGetNextIrpStackLocation(Irp);
+
+ //
+ // Copy the stack down a notch
+ //
+
+ *nextStack = *currentStack;
+
+ IoSetCompletionRoutine(
+ Irp,
+ CdRomClassIoctlCompletion,
+ deviceControlEvent,
+ TRUE,
+ TRUE,
+ TRUE
+ );
+
+ IoSetNextIrpStackLocation(Irp);
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = 0;
+
+ //
+ // Override volume verifies on this stack location so that we
+ // will be forced through the synchronization. Once this location
+ // goes away we get the old value back
+ //
+
+ nextStack->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
+
+ IoMarkIrpPending(Irp);
+
+ IoStartPacket(DeviceObject, Irp, NULL, NULL);
+
+ //
+ // Wait for CdRomClassIoctlCompletion to set the event. This
+ // ensures serialization remains intact for these unhandled device
+ // controls.
+ //
+
+ KeWaitForSingleObject(
+ deviceControlEvent,
+ Suspended,
+ KernelMode,
+ FALSE,
+ NULL);
+
+ ExFreePool(deviceControlEvent);
+
+ DebugPrint((2, "CdRomDeviceControl: irp %#08lx synchronized\n", Irp));
+
+ //
+ // If an error occured then propagate that back up - we are no longer
+ // guaranteed synchronization and the upper layers will have to
+ // retry.
+ //
+ // If no error occured, call down to the class driver directly
+ // then start up the next request.
+ //
+
+ if(Irp->IoStatus.Status == STATUS_SUCCESS) {
+
+ status = ScsiClassDeviceControl(DeviceObject, Irp);
+
+ KeRaiseIrql(DISPATCH_LEVEL, &irql);
+
+ IoStartNextPacket(DeviceObject, FALSE);
+
+ KeLowerIrql(irql);
+ }
+ }
+
+ return status;
+ }
+
+ } // end switch()
+
+ if (status == STATUS_VERIFY_REQUIRED) {
+
+ //
+ // If the status is verified required and this request
+ // should bypass verify required then retry the request.
+ //
+
+ if (irpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME) {
+
+ status = STATUS_IO_DEVICE_ERROR;
+ goto RetryControl;
+
+ }
+ }
+
+ if (IoIsErrorUserInduced(status)) {
+
+ IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
+
+ }
+
+ //
+ // Update IRP with completion status.
+ //
+
+ Irp->IoStatus.Status = status;
+
+ //
+ // Complete the request.
+ //
+
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+ DebugPrint((2, "CdRomDeviceControl: Status is %lx\n", status));
+ return status;
+
+} // end ScsiCdRomDeviceControl()
+
+\f
+VOID
+STDCALL
+ScanForSpecial(
+ PDEVICE_OBJECT DeviceObject,
+ PINQUIRYDATA InquiryData,
+ PIO_SCSI_CAPABILITIES PortCapabilities
+ )
+
+/*++
+
+Routine Description:
+
+ This function checks to see if an SCSI logical unit requires an special
+ initialization or error processing.
+
+Arguments:
+
+ DeviceObject - Supplies the device object to be tested.
+
+ InquiryData - Supplies the inquiry data returned by the device of interest.
+
+ PortCapabilities - Supplies the capabilities of the device object.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
+ PCDROM_DATA cdData = (PCDROM_DATA)(deviceExtension+1);
+
+ //
+ // Look for a Hitachi CDR-1750. Read-ahead must be disabled in order
+ // to get this cdrom drive to work on scsi adapters that use PIO.
+ //
+
+ if ((strncmp(InquiryData->VendorId, "HITACHI CDR-1750S", strlen("HITACHI CDR-1750S")) == 0 ||
+ strncmp(InquiryData->VendorId, "HITACHI CDR-3650/1650S", strlen("HITACHI CDR-3650/1650S")) == 0)
+ && PortCapabilities->AdapterUsesPio) {
+
+ DebugPrint((1, "CdRom ScanForSpecial: Found Hitachi CDR-1750S.\n"));
+
+ //
+ // Setup an error handler to reinitialize the cd rom after it is reset.
+ //
+
+ deviceExtension->ClassError = HitachProcessError;
+
+ } else if (( RtlCompareMemory( InquiryData->VendorId,"FUJITSU", 7 ) == 7 ) &&
+ (( RtlCompareMemory( InquiryData->ProductId,"FMCD-101", 8 ) == 8 ) ||
+ ( RtlCompareMemory( InquiryData->ProductId,"FMCD-102", 8 ) == 8 ))) {
+
+ //
+ // When Read command is issued to FMCD-101 or FMCD-102 and there is a music
+ // cd in it. It takes longer time than SCSI_CDROM_TIMEOUT before returning
+ // error status.
+ //
+
+ deviceExtension->TimeOutValue = 20;
+
+ } else if (( RtlCompareMemory( InquiryData->VendorId,"TOSHIBA", 7) == 7) &&
+ (( RtlCompareMemory( InquiryData->ProductId,"CD-ROM XM-34", 12) == 12))) {
+
+ SCSI_REQUEST_BLOCK srb;
+ PCDB cdb;
+ ULONG length;
+ PUCHAR buffer;
+ NTSTATUS status;
+
+ //
+ // Set the density code and the error handler.
+ //
+
+ length = (sizeof(MODE_READ_RECOVERY_PAGE) + MODE_BLOCK_DESC_LENGTH + MODE_HEADER_LENGTH);
+
+ RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
+
+ //
+ // Build the MODE SENSE CDB.
+ //
+
+ srb.CdbLength = 6;
+ cdb = (PCDB)srb.Cdb;
+
+ //
+ // Set timeout value from device extension.
+ //
+
+ srb.TimeOutValue = deviceExtension->TimeOutValue;
+
+ cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
+ cdb->MODE_SENSE.PageCode = 0x1;
+ cdb->MODE_SENSE.AllocationLength = (UCHAR)length;
+
+ buffer = ExAllocatePool(NonPagedPoolCacheAligned, (sizeof(MODE_READ_RECOVERY_PAGE) + MODE_BLOCK_DESC_LENGTH + MODE_HEADER_LENGTH));
+ if (!buffer) {
+ return;
+ }
+
+ status = ScsiClassSendSrbSynchronous(DeviceObject,
+ &srb,
+ buffer,
+ length,
+ FALSE);
+
+ ((PERROR_RECOVERY_DATA)buffer)->BlockDescriptor.DensityCode = 0x83;
+ ((PERROR_RECOVERY_DATA)buffer)->Header.ModeDataLength = 0x0;
+
+ RtlCopyMemory(&cdData->u1.Header, buffer, sizeof(ERROR_RECOVERY_DATA));
+
+ RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
+
+ //
+ // Build the MODE SENSE CDB.
+ //
+
+ srb.CdbLength = 6;
+ cdb = (PCDB)srb.Cdb;
+
+ //
+ // Set timeout value from device extension.
+ //
+
+ srb.TimeOutValue = deviceExtension->TimeOutValue;
+
+ cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
+ cdb->MODE_SELECT.PFBit = 1;
+ cdb->MODE_SELECT.ParameterListLength = (UCHAR)length;
+
+ status = ScsiClassSendSrbSynchronous(DeviceObject,
+ &srb,
+ buffer,
+ length,
+ TRUE);
+
+ if (!NT_SUCCESS(status)) {
+ DebugPrint((1,
+ "Cdrom.ScanForSpecial: Setting density code on Toshiba failed [%x]\n",
+ status));
+ }
+
+ deviceExtension->ClassError = ToshibaProcessError;
+
+ ExFreePool(buffer);
+
+ }
+
+ //
+ // Determine special CD-DA requirements.
+ //
+
+ if (RtlCompareMemory( InquiryData->VendorId,"PLEXTOR",7) == 7) {
+ cdData->XAFlags |= PLEXTOR_CDDA;
+ } else if (RtlCompareMemory ( InquiryData->VendorId,"NEC",3) == 3) {
+ cdData->XAFlags |= NEC_CDDA;
+ }
+
+ return;
+}
+
+\f
+VOID
+STDCALL
+HitachProcessError(
+ PDEVICE_OBJECT DeviceObject,
+ PSCSI_REQUEST_BLOCK Srb,
+ NTSTATUS *Status,
+ BOOLEAN *Retry
+ )
+/*++
+
+Routine Description:
+
+ This routine checks the type of error. If the error indicates CD-ROM the
+ CD-ROM needs to be reinitialized then a Mode sense command is sent to the
+ device. This command disables read-ahead for the device.
+
+Arguments:
+
+ DeviceObject - Supplies a pointer to the device object.
+
+ Srb - Supplies a pointer to the failing Srb.
+
+ Status - Not used.
+
+ Retry - Not used.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
+ PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer;
+ LARGE_INTEGER largeInt;
+ PUCHAR modePage;
+ PIO_STACK_LOCATION irpStack;
+ PIRP irp;
+ PSCSI_REQUEST_BLOCK srb;
+ PCOMPLETION_CONTEXT context;
+ PCDB cdb;
+ ULONG alignment;
+
+ UNREFERENCED_PARAMETER(Status);
+ UNREFERENCED_PARAMETER(Retry);
+
+ largeInt.QuadPart = (LONGLONG) 1;
+
+ //
+ // Check the status. The initialization command only needs to be sent
+ // if UNIT ATTENTION is returned.
+ //
+
+ if (!(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID)) {
+
+ //
+ // The drive does not require reinitialization.
+ //
+
+ return;
+ }
+
+ //
+ // Found a bad HITACHI cd-rom. These devices do not work with PIO
+ // adapters when read-ahead is enabled. Read-ahead is disabled by
+ // a mode select command. The mode select page code is zero and the
+ // length is 6 bytes. All of the other bytes should be zero.
+ //
+
+
+ if ((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_UNIT_ATTENTION) {
+
+ DebugPrint((1, "HitachiProcessError: Reinitializing the CD-ROM.\n"));
+
+ //
+ // Send the special mode select command to disable read-ahead
+ // on the CD-ROM reader.
+ //
+
+ alignment = DeviceObject->AlignmentRequirement ?
+ DeviceObject->AlignmentRequirement : 1;
+
+ context = ExAllocatePool(
+ NonPagedPool,
+ sizeof(COMPLETION_CONTEXT) + HITACHI_MODE_DATA_SIZE + alignment
+ );
+
+ if (context == NULL) {
+
+ //
+ // If there is not enough memory to fulfill this request,
+ // simply return. A subsequent retry will fail and another
+ // chance to start the unit.
+ //
+
+ return;
+ }
+
+ context->DeviceObject = DeviceObject;
+ srb = &context->Srb;
+
+ RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
+
+ //
+ // Write length to SRB.
+ //
+
+ srb->Length = SCSI_REQUEST_BLOCK_SIZE;
+
+ //
+ // Set up SCSI bus address.
+ //
+
+ srb->PathId = deviceExtension->PathId;
+ srb->TargetId = deviceExtension->TargetId;
+ srb->Lun = deviceExtension->Lun;
+
+ srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
+ srb->TimeOutValue = deviceExtension->TimeOutValue;
+
+ //
+ // Set the transfer length.
+ //
+
+ srb->DataTransferLength = HITACHI_MODE_DATA_SIZE;
+ srb->SrbFlags = SRB_FLAGS_DATA_OUT | SRB_FLAGS_DISABLE_AUTOSENSE | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
+
+ //
+ // The data buffer must be aligned.
+ //
+
+ srb->DataBuffer = (PVOID) (((ULONG) (context + 1) + (alignment - 1)) &
+ ~(alignment - 1));
+
+
+ //
+ // Build the HITACHI read-ahead mode select CDB.
+ //
+
+ srb->CdbLength = 6;
+ cdb = (PCDB)srb->Cdb;
+ cdb->MODE_SENSE.LogicalUnitNumber = srb->Lun;
+ cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SELECT;
+ cdb->MODE_SENSE.AllocationLength = HITACHI_MODE_DATA_SIZE;
+
+ //
+ // Initialize the mode sense data.
+ //
+
+ modePage = srb->DataBuffer;
+
+ RtlZeroMemory(modePage, HITACHI_MODE_DATA_SIZE);
+
+ //
+ // Set the page length field to 6.
+ //
+
+ modePage[5] = 6;
+
+ //
+ // Build the asynchronous request to be sent to the port driver.
+ //
+
+ irp = IoBuildAsynchronousFsdRequest(IRP_MJ_WRITE,
+ DeviceObject,
+ srb->DataBuffer,
+ srb->DataTransferLength,
+ &largeInt,
+ NULL);
+
+ IoSetCompletionRoutine(irp,
+ (PIO_COMPLETION_ROUTINE)ScsiClassAsynchronousCompletion,
+ context,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ irpStack = IoGetNextIrpStackLocation(irp);
+
+ irpStack->MajorFunction = IRP_MJ_SCSI;
+
+ srb->OriginalRequest = irp;
+
+ //
+ // Save SRB address in next stack for port driver.
+ //
+
+ irpStack->Parameters.Scsi.Srb = (PVOID)srb;
+
+ //
+ // Set up IRP Address.
+ //
+
+ (VOID)IoCallDriver(deviceExtension->PortDeviceObject, irp);
+
+ }
+}
+
+\f
+NTSTATUS
+STDCALL
+ToshibaProcessErrorCompletion(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp,
+ PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ Completion routine for the ClassError routine to handle older Toshiba units
+ that require setting the density code.
+
+Arguments:
+
+ DeviceObject - Supplies a pointer to the device object.
+
+ Irp - Pointer to irp created to set the density code.
+
+ Context - Supplies a pointer to the Mode Select Srb.
+
+
+Return Value:
+
+ STATUS_MORE_PROCESSING_REQUIRED
+
+--*/
+
+{
+
+ PSCSI_REQUEST_BLOCK srb = Context;
+
+ //
+ // Check for a frozen queue.
+ //
+
+ if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
+
+ //
+ // Unfreeze the queue getting the device object from the context.
+ //
+
+ ScsiClassReleaseQueue(DeviceObject);
+ }
+
+ //
+ // Free all of the allocations.
+ //
+
+ ExFreePool(srb->DataBuffer);
+ ExFreePool(srb);
+ IoFreeMdl(Irp->MdlAddress);
+ IoFreeIrp(Irp);
+
+ //
+ // Indicate the I/O system should stop processing the Irp completion.
+ //
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+\f
+VOID
+STDCALL
+ToshibaProcessError(
+ PDEVICE_OBJECT DeviceObject,
+ PSCSI_REQUEST_BLOCK Srb,
+ NTSTATUS *Status,
+ BOOLEAN *Retry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine checks the type of error. If the error indicates a unit attention,
+ the density code needs to be set via a Mode select command.
+
+Arguments:
+
+ DeviceObject - Supplies a pointer to the device object.
+
+ Srb - Supplies a pointer to the failing Srb.
+
+ Status - Not used.
+
+ Retry - Not used.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
+ PCDROM_DATA cdData = (PCDROM_DATA)(deviceExtension+1);
+ PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer;
+ PIO_STACK_LOCATION irpStack;
+ PIRP irp;
+ PSCSI_REQUEST_BLOCK srb;
+ ULONG length;
+ PCDB cdb;
+ PUCHAR dataBuffer;
+
+
+ if (!(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID)) {
+ return;
+ }
+
+ //
+ // The Toshiba's require the density code to be set on power up and media changes.
+ //
+
+ if ((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_UNIT_ATTENTION) {
+
+
+ irp = IoAllocateIrp((CCHAR)(deviceExtension->DeviceObject->StackSize+1),
+ FALSE);
+
+ if (!irp) {
+ return;
+ }
+
+ srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
+ if (!srb) {
+ IoFreeIrp(irp);
+ return;
+ }
+
+
+ length = sizeof(ERROR_RECOVERY_DATA);
+ dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, length);
+ if (!dataBuffer) {
+ ExFreePool(srb);
+ IoFreeIrp(irp);
+ return;
+ }
+
+ irp->MdlAddress = IoAllocateMdl(dataBuffer,
+ length,
+ FALSE,
+ FALSE,
+ (PIRP) NULL);
+
+ if (!irp->MdlAddress) {
+ ExFreePool(srb);
+ ExFreePool(dataBuffer);
+ IoFreeIrp(irp);
+ return;
+ }
+
+ //
+ // Prepare the MDL
+ //
+
+ MmBuildMdlForNonPagedPool(irp->MdlAddress);
+
+ RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
+
+ srb->DataBuffer = dataBuffer;
+ cdb = (PCDB)srb->Cdb;
+
+ //
+ // Set up the irp.
+ //
+
+ IoSetNextIrpStackLocation(irp);
+ irp->IoStatus.Status = STATUS_SUCCESS;
+ irp->IoStatus.Information = 0;
+ irp->Flags = 0;
+ irp->UserBuffer = NULL;
+
+ //
+ // Save the device object and irp in a private stack location.
+ //
+
+ irpStack = IoGetCurrentIrpStackLocation(irp);
+ irpStack->DeviceObject = deviceExtension->DeviceObject;
+
+ //
+ // Construct the IRP stack for the lower level driver.
+ //
+
+ irpStack = IoGetNextIrpStackLocation(irp);
+ irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_OUT;
+ irpStack->Parameters.Scsi.Srb = srb;
+
+ IoSetCompletionRoutine(irp,
+ ToshibaProcessErrorCompletion,
+ srb,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ srb->Length = SCSI_REQUEST_BLOCK_SIZE;
+ srb->PathId = deviceExtension->PathId;
+ srb->TargetId = deviceExtension->TargetId;
+ srb->Lun = deviceExtension->Lun;
+ srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
+ srb->Cdb[1] |= deviceExtension->Lun << 5;
+ srb->SrbStatus = srb->ScsiStatus = 0;
+ srb->NextSrb = 0;
+ srb->OriginalRequest = irp;
+ srb->SenseInfoBufferLength = 0;
+
+ //
+ // Set the transfer length.
+ //
+
+ srb->DataTransferLength = length;
+ srb->SrbFlags = SRB_FLAGS_DATA_OUT | SRB_FLAGS_DISABLE_AUTOSENSE | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
+
+
+ srb->CdbLength = 6;
+ cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
+ cdb->MODE_SELECT.PFBit = 1;
+ cdb->MODE_SELECT.ParameterListLength = (UCHAR)length;
+
+ //
+ // Copy the Mode page into the databuffer.
+ //
+
+ RtlCopyMemory(srb->DataBuffer, &cdData->u1.Header, length);
+
+ //
+ // Set the density code.
+ //
+
+ ((PERROR_RECOVERY_DATA)srb->DataBuffer)->BlockDescriptor.DensityCode = 0x83;
+
+ IoCallDriver(deviceExtension->PortDeviceObject, irp);
+ }
+}
+
+\f
+BOOLEAN
+STDCALL
+CdRomIsPlayActive(
+ IN PDEVICE_OBJECT DeviceObject
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines if the cd is currently playing music.
+
+Arguments:
+
+ DeviceObject - Device object to test.
+
+Return Value:
+
+ TRUE if the device is playing music.
+
+--*/
+{
+ PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
+ PIRP irp;
+ IO_STATUS_BLOCK ioStatus;
+ KEVENT event;
+ NTSTATUS status;
+ PSUB_Q_CURRENT_POSITION currentBuffer;
+
+ if (!PLAY_ACTIVE(deviceExtension)) {
+ return(FALSE);
+ }
+
+ currentBuffer = ExAllocatePool(NonPagedPoolCacheAligned, sizeof(SUB_Q_CURRENT_POSITION));
+
+ if (currentBuffer == NULL) {
+ return(FALSE);
+ }
+
+ ((PCDROM_SUB_Q_DATA_FORMAT) currentBuffer)->Format = IOCTL_CDROM_CURRENT_POSITION;
+ ((PCDROM_SUB_Q_DATA_FORMAT) currentBuffer)->Track = 0;
+
+ //
+ // Create notification event object to be used to signal the
+ // request completion.
+ //
+
+ KeInitializeEvent(&event, NotificationEvent, FALSE);
+
+ //
+ // Build the synchronous request to be sent to the port driver
+ // to perform the request.
+ //
+
+ irp = IoBuildDeviceIoControlRequest(IOCTL_CDROM_READ_Q_CHANNEL,
+ deviceExtension->DeviceObject,
+ currentBuffer,
+ sizeof(CDROM_SUB_Q_DATA_FORMAT),
+ currentBuffer,
+ sizeof(SUB_Q_CURRENT_POSITION),
+ FALSE,
+ &event,
+ &ioStatus);
+
+ if (irp == NULL) {
+ ExFreePool(currentBuffer);
+ return FALSE;
+ }
+
+ //
+ // Pass request to port driver and wait for request to complete.
+ //
+
+ status = IoCallDriver(deviceExtension->DeviceObject, irp);
+
+ if (status == STATUS_PENDING) {
+ KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
+ status = ioStatus.Status;
+ }
+
+ if (!NT_SUCCESS(status)) {
+ ExFreePool(currentBuffer);
+ return FALSE;
+ }
+
+ ExFreePool(currentBuffer);
+
+ return(PLAY_ACTIVE(deviceExtension));
+
+}
+
+
+\f
+NTSTATUS
+STDCALL
+CdRomMediaChangeCompletion(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp,
+ PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles the completion of the test unit ready irps
+ used to determine if the media has changed. If the media has
+ changed, this code signals the named event to wake up other
+ system services that react to media change (aka AutoPlay).
+
+Arguments:
+
+ DeviceObject - the object for the completion
+ Irp - the IRP being completed
+ Context - the SRB from the IRP
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+
+{
+ PSCSI_REQUEST_BLOCK srb = (PSCSI_REQUEST_BLOCK) Context;
+ PIO_STACK_LOCATION cdStack = IoGetCurrentIrpStackLocation(Irp);
+ PIO_STACK_LOCATION irpNextStack = IoGetNextIrpStackLocation(Irp);
+ PDEVICE_EXTENSION deviceExtension;
+ PDEVICE_EXTENSION physicalExtension;
+ PSENSE_DATA senseBuffer;
+ PCDROM_DATA cddata;
+
+ ASSERT(Irp);
+ ASSERT(cdStack);
+ DeviceObject = cdStack->DeviceObject;
+ ASSERT(DeviceObject);
+
+ deviceExtension = DeviceObject->DeviceExtension;
+ physicalExtension = deviceExtension->PhysicalDevice->DeviceExtension;
+ cddata = (PCDROM_DATA)(deviceExtension + 1);
+
+ ASSERT(cddata->MediaChangeIrp == NULL);
+
+ //
+ // If the sense data field is valid, look for a media change.
+ // otherwise this iteration of the polling will just assume nothing
+ // changed.
+ //
+
+ DebugPrint((3, "CdRomMediaChangeHandler: Completing Autorun Irp 0x%lx "
+ "for device %d\n",
+ Irp, deviceExtension->DeviceNumber));
+
+ if (srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) {
+ if (srb->SenseInfoBufferLength >= FIELD_OFFSET(SENSE_DATA, CommandSpecificInformation)) {
+
+ //
+ // See if this is a media change.
+ //
+
+ senseBuffer = srb->SenseInfoBuffer;
+ if ((senseBuffer->SenseKey & 0x0f) == SCSI_SENSE_UNIT_ATTENTION) {
+ if (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_MEDIUM_CHANGED) {
+
+ DebugPrint((1, "CdRomMediaChangeCompletion: New media inserted "
+ "into CdRom%d [irp = 0x%lx]\n",
+ deviceExtension->DeviceNumber, Irp));
+
+ //
+ // Media change event occurred - signal the named event.
+ //
+
+ KeSetEvent(deviceExtension->MediaChangeEvent,
+ (KPRIORITY) 0,
+ FALSE);
+
+ deviceExtension->MediaChangeNoMedia = FALSE;
+
+ }
+
+ if (DeviceObject->Vpb->Flags & VPB_MOUNTED) {
+
+ //
+ // Must remember the media changed and force the
+ // file system to verify on next access
+ //
+
+ DeviceObject->Flags |= DO_VERIFY_VOLUME;
+ }
+
+ physicalExtension->MediaChangeCount++;
+
+ } else if(((senseBuffer->SenseKey & 0x0f) == SCSI_SENSE_NOT_READY)&&
+ (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_NO_MEDIA_IN_DEVICE)&&
+ (!deviceExtension->MediaChangeNoMedia)){
+
+ //
+ // If there was no media in the device then signal the waiters if
+ // we haven't already done so before.
+ //
+
+ DebugPrint((1, "CdRomMediaChangeCompletion: No media in device"
+ "CdRom%d [irp = 0x%lx]\n",
+ deviceExtension->DeviceNumber, Irp));
+
+ KeSetEvent(deviceExtension->MediaChangeEvent,
+ (KPRIORITY) 0,
+ FALSE);
+
+ deviceExtension->MediaChangeNoMedia = TRUE;
+
+ }
+ }
+ } else if((srb->SrbStatus == SRB_STATUS_SUCCESS)&&
+ (deviceExtension->MediaChangeNoMedia)) {
+ //
+ // We didn't have any media before and now the requests are succeeding
+ // we probably missed the Media change somehow. Signal the change
+ // anyway
+ //
+
+ DebugPrint((1, "CdRomMediaChangeCompletion: Request completed normally"
+ "for CdRom%d which was marked w/NoMedia [irp = 0x%lx]\n",
+ deviceExtension->DeviceNumber, Irp));
+
+ KeSetEvent(deviceExtension->MediaChangeEvent,
+ (KPRIORITY) 0,
+ FALSE);
+
+ deviceExtension->MediaChangeNoMedia = FALSE;
+
+ }
+
+ if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
+ ScsiClassReleaseQueue(deviceExtension->DeviceObject);
+ }
-/* INCLUDES *****************************************************************/
+ //
+ // Remember the IRP and SRB for use the next time.
+ //
-#include <ntddk.h>
-#include <scsi.h>
-#include <ntddscsi.h>
-#include <ntdddisk.h>
-#include <ntddcdrm.h>
-#include <include/class2.h>
-#include <stdio.h>
+ irpNextStack->Parameters.Scsi.Srb = srb;
+ cddata->MediaChangeIrp = Irp;
-#define NDEBUG
-#include <debug.h>
+ if (deviceExtension->ClassError) {
-#define VERSION "0.0.1"
+ NTSTATUS status;
+ BOOLEAN retry;
+ //
+ // Throw away the status and retry values. Just give the error routine a chance
+ // to do what it needs to.
+ //
-#define SCSI_CDROM_TIMEOUT 10 /* Default timeout: 10 seconds */
+ deviceExtension->ClassError(DeviceObject,
+ srb,
+ &status,
+ &retry);
+ }
+ IoStartNextPacket(DeviceObject, FALSE);
-typedef struct _ERROR_RECOVERY_DATA6
-{
- MODE_PARAMETER_HEADER Header;
- MODE_READ_RECOVERY_PAGE ReadRecoveryPage;
-} ERROR_RECOVERY_DATA6, *PERROR_RECOVERY_DATA6;
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+\f
+VOID
+STDCALL
+CdRomTickHandler(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PVOID Context
+ )
+/*++
-typedef struct _ERROR_RECOVERY_DATA10
-{
- MODE_PARAMETER_HEADER10 Header;
- MODE_READ_RECOVERY_PAGE ReadRecoveryPage;
-} ERROR_RECOVERY_DATA10, *PERROR_RECOVERY_DATA10;
+Routine Description:
-typedef struct _MODE_CAPABILITIES_PAGE2
-{
- UCHAR PageCode:6;
- UCHAR Reserved1:1;
- UCHAR PSBit:1;
- UCHAR PageLength;
- UCHAR Reserved2[2];
- UCHAR Capabilities[4];
- UCHAR MaximumSpeedSupported[2];
- UCHAR Reserved3;
- UCHAR NumberVolumeLevels;
- UCHAR BufferSize[2];
- UCHAR CurrentSpeed[2];
- UCHAR Reserved4;
- UCHAR Reserved5:1;
- UCHAR DigitalOutput:4;
- UCHAR Reserved6:3;
- UCHAR Reserved7[2];
-} MODE_CAPABILITIES_PAGE2, *PMODE_CAPABILITIES_PAGE2;
-
-typedef struct _MODE_CAPABILITIES_DATA6
-{
- MODE_PARAMETER_HEADER Header;
- MODE_CAPABILITIES_PAGE2 CababilitiesPage;
-} MODE_CAPABILITIES_DATA6, *PMODE_CAPABILITIES_DATA6;
+ This routine handles the once per second timer provided by the
+ Io subsystem. It is only used when the cdrom device itself is
+ a candidate for autoplay support. It should never be called if
+ the cdrom device is a changer device.
-typedef struct _MODE_CAPABILITIES_DATA10
-{
- MODE_PARAMETER_HEADER10 Header;
- MODE_CAPABILITIES_PAGE2 CababilitiesPage;
-} MODE_CAPABILITIES_DATA10, *PMODE_CAPABILITIES_DATA10;
+Arguments:
-typedef struct _CDROM_DATA
-{
- BOOLEAN PlayActive;
- BOOLEAN RawAccess;
- USHORT XaFlags;
+ DeviceObject - what to check.
+ Context - not used.
-} CDROM_DATA, *PCDROM_DATA;
+Return Value:
-/* CDROM_DATA.XaFlags */
-#define XA_USE_6_BYTE 0x0001
-#define XA_USE_10_BYTE 0x0002
-#define XA_USE_READ_CD 0x0004
-#define XA_NOT_SUPPORTED 0x0008
-
-
-BOOLEAN STDCALL
-CdromClassFindDevices(IN PDRIVER_OBJECT DriverObject,
- IN PUNICODE_STRING RegistryPath,
- IN PCLASS_INIT_DATA InitializationData,
- IN PDEVICE_OBJECT PortDeviceObject,
- IN ULONG PortNumber);
-
-BOOLEAN STDCALL
-CdromClassCheckDevice(IN PINQUIRYDATA InquiryData);
-
-NTSTATUS STDCALL
-CdromClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp);
-
-static VOID
-CdromClassCreateMediaChangeEvent(IN PDEVICE_EXTENSION DeviceExtension,
- IN ULONG DeviceNumber);
-
-static NTSTATUS
-CdromClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
- IN PUNICODE_STRING RegistryPath,
- IN PDEVICE_OBJECT PortDeviceObject,
- IN ULONG PortNumber,
- IN ULONG DeviceNumber,
- IN PIO_SCSI_CAPABILITIES Capabilities,
- IN PSCSI_INQUIRY_DATA InquiryData,
- IN PCLASS_INIT_DATA InitializationData);
-
-
-NTSTATUS STDCALL
-CdromClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp);
-
-VOID STDCALL
-CdromClassStartIo (IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp);
-
-NTSTATUS STDCALL
-CdromDeviceControlCompletion (IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp,
- IN PVOID Context);
-
-VOID STDCALL
-CdromTimerRoutine(IN PDEVICE_OBJECT DeviceObject,
- IN PVOID Context);
-
-VOID STDCALL
-CdromWorkItem(IN PDEVICE_OBJECT DeviceObject,
- IN PVOID Context);
-
-
-/* FUNCTIONS ****************************************************************/
-
-/**********************************************************************
- * NAME EXPORTED
- * DriverEntry
- *
- * DESCRIPTION:
- * This function initializes the driver, locates and claims
- * hardware resources, and creates various NT objects needed
- * to process I/O requests.
- *
- * RUN LEVEL:
- * PASSIVE_LEVEL
- *
- * ARGUMENTS:
- * DriverObject
- * System allocated Driver Object for this driver
- * RegistryPath
- * Name of registry driver service key
- *
- * RETURNS:
- * Status.
- */
+ None.
+
+--*/
-NTSTATUS STDCALL
-DriverEntry(IN PDRIVER_OBJECT DriverObject,
- IN PUNICODE_STRING RegistryPath)
{
- CLASS_INIT_DATA InitData;
-
- DPRINT("CD-ROM Class Driver %s\n",
- VERSION);
- DPRINT("RegistryPath '%wZ'\n",
- RegistryPath);
-
- InitData.InitializationDataSize = sizeof(CLASS_INIT_DATA);
- InitData.DeviceExtensionSize = sizeof(DEVICE_EXTENSION) + sizeof(CDROM_DATA);
- InitData.DeviceType = FILE_DEVICE_CD_ROM;
- InitData.DeviceCharacteristics = FILE_REMOVABLE_MEDIA | FILE_READ_ONLY_DEVICE;
-
- InitData.ClassError = NULL;
- InitData.ClassReadWriteVerification = CdromClassCheckReadWrite;
- InitData.ClassFindDeviceCallBack = CdromClassCheckDevice;
- InitData.ClassFindDevices = CdromClassFindDevices;
- InitData.ClassDeviceControl = CdromClassDeviceControl;
- InitData.ClassShutdownFlush = NULL;
- InitData.ClassCreateClose = NULL;
- InitData.ClassStartIo = CdromClassStartIo;
-
- return(ScsiClassInitialize(DriverObject,
- RegistryPath,
- &InitData));
-}
+ PIRP irp;
+ PIRP heldIrpList;
+ PIRP nextIrp;
+ PLIST_ENTRY listEntry;
+ PCDROM_DATA cddata;
+ PIO_STACK_LOCATION irpStack;
+ PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
+
+ cddata = (PCDROM_DATA)(deviceExtension + 1);
+
+ if (cddata->MediaChange) {
+ if (cddata->MediaChangeIrp != NULL) {
+
+ //
+ // Media change support is active and the IRP is waiting.
+ // Decrement the timer.
+ // There is no MP protection on the timer counter. This
+ // code is the only code that will manipulate the timer
+ // and only one instance of it should be running at any
+ // given time.
+ //
+
+ cddata->MediaChangeCountDown--;
+
+#ifdef DBG
+ cddata->MediaChangeIrpTimeInUse = 0;
+ cddata->MediaChangeIrpLost = FALSE;
+#endif
+ if (!cddata->MediaChangeCountDown) {
+ PSCSI_REQUEST_BLOCK srb;
+ PIO_STACK_LOCATION irpNextStack;
+ PCDB cdb;
+
+ //
+ // Reset the timer.
+ //
+
+ cddata->MediaChangeCountDown = MEDIA_CHANGE_DEFAULT_TIME;
+
+ //
+ // Prepare the IRP for the test unit ready
+ //
+
+ irp = cddata->MediaChangeIrp;
+ cddata->MediaChangeIrp = NULL;
+
+ irp->IoStatus.Status = STATUS_SUCCESS;
+ irp->IoStatus.Information = 0;
+ irp->Flags = 0;
+ irp->UserBuffer = NULL;
+
+ //
+ // If the irp is sent down when the volume needs to be
+ // verified, CdRomUpdateGeometryCompletion won't complete
+ // it since it's not associated with a thread. Marking
+ // it to override the verify causes it always be sent
+ // to the port driver
+ //
+
+ irpStack = IoGetCurrentIrpStackLocation(irp);
+ irpStack->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
+
+ irpNextStack = IoGetNextIrpStackLocation(irp);
+ irpNextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ irpNextStack->Parameters.DeviceIoControl.IoControlCode =
+ IOCTL_SCSI_EXECUTE_NONE;
+
+ //
+ // Prepare the SRB for execution.
+ //
+
+ srb = irpNextStack->Parameters.Scsi.Srb;
+ srb->SrbStatus = srb->ScsiStatus = 0;
+ srb->NextSrb = 0;
+ srb->Length = SCSI_REQUEST_BLOCK_SIZE;
+ srb->PathId = deviceExtension->PathId;
+ srb->TargetId = deviceExtension->TargetId;
+ srb->Lun = deviceExtension->Lun;
+ srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
+ srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER |
+ SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
+ srb->DataTransferLength = 0;
+ srb->OriginalRequest = irp;
+
+ RtlZeroMemory(srb->SenseInfoBuffer, SENSE_BUFFER_SIZE);
+ srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
+
+ cdb = (PCDB) &srb->Cdb[0];
+ cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
+ cdb->CDB6GENERIC.LogicalUnitNumber = srb->Lun;
+
+ //
+ // Setup the IRP to perform a test unit ready.
+ //
+
+ IoSetCompletionRoutine(irp,
+ CdRomMediaChangeCompletion,
+ srb,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ //
+ // Issue the request.
+ //
+
+ IoStartPacket(DeviceObject, irp, NULL, NULL);
+ }
+ } else {
+
+#ifdef DBG
+ if(cddata->MediaChangeIrpLost == FALSE) {
+ if(cddata->MediaChangeIrpTimeInUse++ >
+ MEDIA_CHANGE_TIMEOUT_TIME) {
+
+ DebugPrint((0, "CdRom%d: AutoPlay has lost it's irp and "
+ "doesn't know where to find it. Leave it "
+ "alone and it'll come home dragging it's "
+ "stack behind it.\n",
+ deviceExtension->DeviceNumber));
+ cddata->MediaChangeIrpLost = TRUE;
+ }
+ }
-/**********************************************************************
- * NAME EXPORTED
- * CdromClassFindDevices
- *
- * DESCRIPTION:
- * This function searches for device that are attached to the
- * given scsi port.
- *
- * RUN LEVEL:
- * PASSIVE_LEVEL
- *
- * ARGUMENTS:
- * DriverObject
- * System allocated Driver Object for this driver
- * RegistryPath
- * Name of registry driver service key.
- * InitializationData
- * Pointer to the main initialization data
- * PortDeviceObject
- * Scsi port device object
- * PortNumber
- * Port number
- *
- * RETURNS:
- * TRUE: At least one disk drive was found
- * FALSE: No disk drive found
- */
+#endif
+ }
+ }
-BOOLEAN STDCALL
-CdromClassFindDevices(IN PDRIVER_OBJECT DriverObject,
- IN PUNICODE_STRING RegistryPath,
- IN PCLASS_INIT_DATA InitializationData,
- IN PDEVICE_OBJECT PortDeviceObject,
- IN ULONG PortNumber)
-{
- PCONFIGURATION_INFORMATION ConfigInfo;
- PIO_SCSI_CAPABILITIES PortCapabilities;
- PSCSI_ADAPTER_BUS_INFO AdapterBusInfo;
- PSCSI_INQUIRY_DATA UnitInfo;
- PINQUIRYDATA InquiryData;
- PCHAR Buffer;
- ULONG Bus;
- ULONG DeviceCount;
- BOOLEAN FoundDevice = FALSE;
- NTSTATUS Status;
-
- DPRINT("CdromClassFindDevices() called.\n");
-
- /* Get port capabilities */
- Status = ScsiClassGetCapabilities(PortDeviceObject,
- &PortCapabilities);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("ScsiClassGetCapabilities() failed! (Status 0x%lX)\n", Status);
- return(FALSE);
- }
-
- DPRINT("PortCapabilities: %p\n", PortCapabilities);
- DPRINT("MaximumTransferLength: %lu\n", PortCapabilities->MaximumTransferLength);
- DPRINT("MaximumPhysicalPages: %lu\n", PortCapabilities->MaximumPhysicalPages);
-
- /* Get inquiry data */
- Status = ScsiClassGetInquiryData(PortDeviceObject,
- (PSCSI_ADAPTER_BUS_INFO *)&Buffer);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("ScsiClassGetInquiryData() failed! (Status 0x%lX)\n", Status);
- return(FALSE);
- }
-
- /* Check whether there are unclaimed devices */
- AdapterBusInfo = (PSCSI_ADAPTER_BUS_INFO)Buffer;
- DeviceCount = ScsiClassFindUnclaimedDevices(InitializationData,
- AdapterBusInfo);
- if (DeviceCount == 0)
- {
- DPRINT("No unclaimed devices!\n");
- return(FALSE);
- }
-
- DPRINT("Found %lu unclaimed devices!\n", DeviceCount);
-
- ConfigInfo = IoGetConfigurationInformation();
- DPRINT("Number of SCSI ports: %lu\n", ConfigInfo->ScsiPortCount);
-
- /* Search each bus of this adapter */
- for (Bus = 0; Bus < (ULONG)AdapterBusInfo->NumberOfBuses; Bus++)
- {
- DPRINT("Searching bus %lu\n", Bus);
-
- UnitInfo = (PSCSI_INQUIRY_DATA)(Buffer + AdapterBusInfo->BusData[Bus].InquiryDataOffset);
-
- while (AdapterBusInfo->BusData[Bus].InquiryDataOffset)
- {
- InquiryData = (PINQUIRYDATA)UnitInfo->InquiryData;
-
- if ((InquiryData->DeviceType == READ_ONLY_DIRECT_ACCESS_DEVICE) &&
- (InquiryData->DeviceTypeQualifier == 0) &&
- (UnitInfo->DeviceClaimed == FALSE))
- {
- DPRINT("Vendor: '%.24s'\n",
- InquiryData->VendorId);
-
- /* Create device objects for disk */
- Status = CdromClassCreateDeviceObject(DriverObject,
- RegistryPath,
- PortDeviceObject,
- PortNumber,
- ConfigInfo->CdRomCount,
- PortCapabilities,
- UnitInfo,
- InitializationData);
- if (NT_SUCCESS(Status))
- {
- ConfigInfo->CdRomCount++;
- FoundDevice = TRUE;
- }
- }
-
- if (UnitInfo->NextInquiryDataOffset == 0)
- break;
-
- UnitInfo = (PSCSI_INQUIRY_DATA)(Buffer + UnitInfo->NextInquiryDataOffset);
- }
- }
-
- ExFreePool(Buffer);
-
- DPRINT("CdromClassFindDevices() done\n");
-
- return(FoundDevice);
-}
+ //
+ // Process all generic timer IRPS in the timer list. As IRPs are pulled
+ // off of the TimerIrpList they must be remembered in the first loop
+ // if they are not sent to the lower driver. After all items have
+ // been pulled off the list, it is possible to put the held IRPs back
+ // into the TimerIrpList.
+ //
+
+ heldIrpList = NULL;
+ if (IsListEmpty(&cddata->TimerIrpList)) {
+ listEntry = NULL;
+ } else {
+ listEntry = ExInterlockedRemoveHeadList(&cddata->TimerIrpList,
+ &cddata->TimerIrpSpinLock);
+ }
+ while (listEntry) {
+ //
+ // There is something in the timer list. Pick up the IRP and
+ // see if it is ready to be submitted.
+ //
-/**********************************************************************
- * NAME EXPORTED
- * CdromClassCheckDevice
- *
- * DESCRIPTION
- * This function checks the InquiryData for the correct device
- * type and qualifier.
- *
- * RUN LEVEL
- * PASSIVE_LEVEL
- *
- * ARGUMENTS
- * InquiryData
- * Pointer to the inquiry data for the device in question.
- *
- * RETURN VALUE
- * TRUE: A disk device was found.
- * FALSE: Otherwise.
- */
+ irp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);
+ irpStack = IoGetCurrentIrpStackLocation(irp);
-BOOLEAN STDCALL
-CdromClassCheckDevice(IN PINQUIRYDATA InquiryData)
-{
- return((InquiryData->DeviceType == READ_ONLY_DIRECT_ACCESS_DEVICE) &&
- (InquiryData->DeviceTypeQualifier == 0));
-}
+ if (irpStack->Parameters.Others.Argument3) {
+ ULONG count;
+ //
+ // Decrement the countdown timer and put the IRP back in the list.
+ //
-/**********************************************************************
- * NAME EXPORTED
- * CdromClassCheckReadWrite
- *
- * DESCRIPTION
- * This function checks the given IRP for correct data.
- *
- * RUN LEVEL
- * PASSIVE_LEVEL
- *
- * ARGUMENTS
- * DeviceObject
- * Pointer to the device.
- * Irp
- * Irp to check.
- *
- * RETURN VALUE
- * STATUS_SUCCESS: The IRP matches the requirements of the given device.
- * Others: Failure.
- */
+ count = (ULONG) irpStack->Parameters.Others.Argument3;
+ count--;
+ irpStack->Parameters.Others.Argument3 = (PVOID) count;
-NTSTATUS STDCALL
-CdromClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp)
-{
- DPRINT("CdromClassCheckReadWrite() called\n");
+ ASSERT(irp->AssociatedIrp.MasterIrp == NULL);
+ if (heldIrpList) {
+ irp->AssociatedIrp.MasterIrp = (PVOID) heldIrpList;
+ }
+ heldIrpList = irp;
- return(STATUS_SUCCESS);
-}
+ } else {
+ //
+ // Submit this IRP to the lower driver. This IRP does not
+ // need to be remembered here. It will be handled again when
+ // it completes.
+ //
-static VOID
-CdromClassCreateMediaChangeEvent(IN PDEVICE_EXTENSION DeviceExtension,
- IN ULONG DeviceNumber)
-{
+ DebugPrint((1, "CdRomTickHandler: Reissuing request %lx (thread = %lx)\n", irp, irp->Tail.Overlay.Thread));
+
+ //
+ // feed this to the appropriate port driver
+ //
+
+ IoCallDriver (deviceExtension->PortDeviceObject, irp);
+
+ }
+
+ //
+ // Pick up the next IRP from the timer list.
+ //
+
+ listEntry = ExInterlockedRemoveHeadList(&cddata->TimerIrpList,
+ &cddata->TimerIrpSpinLock);
+ }
+
+ //
+ // Move all held IRPs back onto the timer list.
+ //
+
+ while (heldIrpList) {
+ //
+ // Save the single list pointer before queueing this IRP.
+ //
- DeviceExtension->MediaChangeEvent =
- IoCreateSynchronizationEvent (NULL,
- &DeviceExtension->MediaChangeEventHandle);
+ nextIrp = (PIRP) heldIrpList->AssociatedIrp.MasterIrp;
+ heldIrpList->AssociatedIrp.MasterIrp = NULL;
- KeClearEvent (DeviceExtension->MediaChangeEvent);
+ //
+ // Return the held IRP to the timer list.
+ //
+
+ ExInterlockedInsertTailList(&cddata->TimerIrpList,
+ &heldIrpList->Tail.Overlay.ListEntry,
+ &cddata->TimerIrpSpinLock);
+
+ //
+ // Continue processing the held IRPs
+ //
+
+ heldIrpList = nextIrp;
+ }
}
+\f
+BOOLEAN
+STDCALL
+CdRomCheckRegistryForMediaChangeValue(
+ IN PUNICODE_STRING RegistryPath,
+ IN ULONG DeviceNumber
+ )
+/*++
-/**********************************************************************
- * NAME EXPORTED
- * CdromClassCreateDeviceObject
- *
- * DESCRIPTION:
- * Create the raw device and any partition devices on this drive
- *
- * RUN LEVEL:
- * PASSIVE_LEVEL
- *
- * ARGUMENTS:
- * DriverObject
- * System allocated Driver Object for this driver.
- * RegistryPath
- * Name of registry driver service key.
- * PortDeviceObject
- * PortNumber
- * DeviceNumber
- * Capabilities
- * InquiryData
- * InitializationData
- *
- * RETURNS:
- * Status.
- */
+Routine Description:
+
+ The user must specify that AutoPlay is to run on the platform
+ by setting the registry value HKEY_LOCAL_MACHINE\System\CurrentControlSet\
+ Services\Cdrom\Autorun:REG_DWORD:1.
+
+ The user can override the global setting to enable or disable Autorun on a
+ specific cdrom device by setting the key HKEY_LOCAL_MACHINE\System\
+ CurrentControlSet\Services\Cdrom\Device<N>\Autorun:REG_DWORD to one or zero.
+ (CURRENTLY UNIMPLEMENTED)
+
+ If this registry value does not exist or contains the value zero then
+ the timer to check for media change does not run.
+
+Arguments:
+
+ RegistryPath - pointer to the unicode string inside
+ ...\CurrentControlSet\Services\Cdrom
+ DeviceNumber - The number of the device object
+
+Return Value:
+
+ TRUE - Autorun is enabled.
+ FALSE - no autorun.
+
+--*/
-static NTSTATUS
-CdromClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
- IN PUNICODE_STRING RegistryPath,
- IN PDEVICE_OBJECT PortDeviceObject,
- IN ULONG PortNumber,
- IN ULONG DeviceNumber,
- IN PIO_SCSI_CAPABILITIES Capabilities,
- IN PSCSI_INQUIRY_DATA InquiryData,
- IN PCLASS_INIT_DATA InitializationData)
{
- PDEVICE_EXTENSION DiskDeviceExtension; /* defined in class2.h */
- PDEVICE_OBJECT DiskDeviceObject;
- PCDROM_DATA CdromData;
- CHAR NameBuffer[80];
- SCSI_REQUEST_BLOCK Srb;
- PUCHAR Buffer;
- ULONG Length;
- PCDB Cdb;
- NTSTATUS Status;
-
- DPRINT("CdromClassCreateDeviceObject() called\n");
-
- /* Claim the cdrom device */
- Status = ScsiClassClaimDevice(PortDeviceObject,
- InquiryData,
- FALSE,
- &PortDeviceObject);
- if (!NT_SUCCESS(Status))
- {
- DbgPrint("Could not claim cdrom device\n");
- return(Status);
- }
-
- /* Create cdrom device */
- sprintf(NameBuffer,
- "\\Device\\CdRom%lu",
- DeviceNumber);
-
- Status = ScsiClassCreateDeviceObject(DriverObject,
- NameBuffer,
- NULL,
- &DiskDeviceObject,
- InitializationData);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("ScsiClassCreateDeviceObject() failed (Status %x)\n", Status);
-
- /* Release (unclaim) the disk */
- ScsiClassClaimDevice(PortDeviceObject,
- InquiryData,
- TRUE,
- NULL);
-
- return(Status);
- }
-
- DiskDeviceObject->Flags |= DO_DIRECT_IO;
- DiskDeviceObject->Characteristics |= FILE_REMOVABLE_MEDIA;
- DiskDeviceObject->StackSize = (CCHAR)PortDeviceObject->StackSize + 1;
-
- if (PortDeviceObject->AlignmentRequirement > DiskDeviceObject->AlignmentRequirement)
- {
- DiskDeviceObject->AlignmentRequirement = PortDeviceObject->AlignmentRequirement;
- }
-
- DiskDeviceExtension = DiskDeviceObject->DeviceExtension;
- DiskDeviceExtension->LockCount = 0;
- DiskDeviceExtension->DeviceNumber = DeviceNumber;
- DiskDeviceExtension->DeviceObject = DiskDeviceObject;
- DiskDeviceExtension->PortDeviceObject = PortDeviceObject;
- DiskDeviceExtension->PhysicalDevice = DiskDeviceObject;
- DiskDeviceExtension->PortCapabilities = Capabilities;
- DiskDeviceExtension->StartingOffset.QuadPart = 0;
- DiskDeviceExtension->PortNumber = (UCHAR)PortNumber;
- DiskDeviceExtension->PathId = InquiryData->PathId;
- DiskDeviceExtension->TargetId = InquiryData->TargetId;
- DiskDeviceExtension->Lun = InquiryData->Lun;
-
- /* zero-out disk data */
- CdromData = (PCDROM_DATA)(DiskDeviceExtension + 1);
- RtlZeroMemory(CdromData,
- sizeof(CDROM_DATA));
-
- DiskDeviceExtension->SenseData = ExAllocatePool(NonPagedPool,
- sizeof(SENSE_DATA));
- if (DiskDeviceExtension->SenseData == NULL)
- {
- DPRINT1("Failed to allocate sense data buffer!\n");
-
- IoDeleteDevice(DiskDeviceObject);
-
- /* Release (unclaim) the disk */
- ScsiClassClaimDevice(PortDeviceObject,
- InquiryData,
- TRUE,
- NULL);
-
- return(STATUS_INSUFFICIENT_RESOURCES);
- }
-
- /* Get timeout value */
- DiskDeviceExtension->TimeOutValue =
- ScsiClassQueryTimeOutRegistryValue(RegistryPath);
- if (DiskDeviceExtension->TimeOutValue == 0)
- DiskDeviceExtension->TimeOutValue = SCSI_CDROM_TIMEOUT;
-
- /* Initialize lookaside list for SRBs */
- ScsiClassInitializeSrbLookasideList(DiskDeviceExtension,
- 4);
-
- /* Get disk geometry */
- DiskDeviceExtension->DiskGeometry = ExAllocatePool(NonPagedPool,
- sizeof(DISK_GEOMETRY));
- if (DiskDeviceExtension->DiskGeometry == NULL)
- {
- DPRINT1("Failed to allocate geometry buffer!\n");
-
- ExDeleteNPagedLookasideList(&DiskDeviceExtension->SrbLookasideListHead);
-
- IoDeleteDevice(DiskDeviceObject);
-
- /* Release (unclaim) the disk */
- ScsiClassClaimDevice(PortDeviceObject,
- InquiryData,
- TRUE,
- NULL);
-
- return(STATUS_INSUFFICIENT_RESOURCES);
- }
-
- /* Read the drive's capacity */
- Status = ScsiClassReadDriveCapacity(DiskDeviceObject);
- if (!NT_SUCCESS(Status) ||
- DiskDeviceExtension->DiskGeometry->BytesPerSector == 0)
- {
- /* Set ISO9660 defaults */
- DiskDeviceExtension->DiskGeometry->BytesPerSector = 2048;
- DiskDeviceExtension->DiskGeometry->MediaType = RemovableMedia;
- DiskDeviceExtension->SectorShift = 11;
- DiskDeviceExtension->PartitionLength.QuadPart = (ULONGLONG)0x7fffffff;
- }
- else
- {
- /* Make sure the BytesPerSector value is a power of 2 */
-// DiskDeviceExtension->DiskGeometry->BytesPerSector = 2048;
- }
-
- DPRINT("SectorSize: %lu\n", DiskDeviceExtension->DiskGeometry->BytesPerSector);
-
- /* Initialize media change support */
- CdromClassCreateMediaChangeEvent (DiskDeviceExtension,
- DeviceNumber);
- if (DiskDeviceExtension->MediaChangeEvent != NULL)
- {
- DPRINT("Allocated media change event!\n");
-
- /* FIXME: Allocate media change IRP and SRB */
- }
-
- /* Use 6 byte xa commands by default */
- CdromData->XaFlags |= XA_USE_6_BYTE;
-
- /* Read 'error recovery page' to get additional drive capabilities */
- Length = sizeof(MODE_READ_RECOVERY_PAGE) + MODE_HEADER_LENGTH;
-
- RtlZeroMemory (&Srb,
- sizeof(SCSI_REQUEST_BLOCK));
- Srb.CdbLength = 6;
- Srb.TimeOutValue = DiskDeviceExtension->TimeOutValue;
-
- Cdb = (PCDB)Srb.Cdb;
- Cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
- Cdb->MODE_SENSE.PageCode = 0x01;
- Cdb->MODE_SENSE.AllocationLength = (UCHAR)Length;
-
- Buffer = ExAllocatePool (NonPagedPool,
- max(sizeof(ERROR_RECOVERY_DATA6),
- max(sizeof(ERROR_RECOVERY_DATA10),
- max(sizeof(MODE_CAPABILITIES_DATA6),
- sizeof(MODE_CAPABILITIES_DATA10)))));
- if (Buffer == NULL)
- {
- DPRINT1("Allocating recovery page buffer failed!\n");
- return STATUS_INSUFFICIENT_RESOURCES;
- }
-
- Status = ScsiClassSendSrbSynchronous (DiskDeviceObject,
- &Srb,
- Buffer,
- Length,
- FALSE);
-
- if (!NT_SUCCESS (Status))
- {
- DPRINT("MODE_SENSE(6) failed\n");
-
- /* Try the 10 byte version */
- Length = sizeof(MODE_READ_RECOVERY_PAGE) + MODE_HEADER_LENGTH10;
-
- RtlZeroMemory (&Srb,
- sizeof(SCSI_REQUEST_BLOCK));
- Srb.CdbLength = 10;
- Srb.TimeOutValue = DiskDeviceExtension->TimeOutValue;
-
- Cdb = (PCDB)Srb.Cdb;
- Cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
- Cdb->MODE_SENSE10.PageCode = 0x01;
- Cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(Length >> 8);
- Cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(Length & 0xFF);
-
- Status = ScsiClassSendSrbSynchronous (DiskDeviceObject,
- &Srb,
- Buffer,
- Length,
- FALSE);
-
- if (Status == STATUS_DATA_OVERRUN)
- {
- DPRINT1("Data overrun\n");
-
- /* FIXME */
- }
- else if (NT_SUCCESS (Status))
- {
- DPRINT("Use 10 byte commands\n");
- CdromData->XaFlags &= XA_USE_6_BYTE;
- CdromData->XaFlags |= XA_USE_10_BYTE;
- }
- else
- {
- DPRINT("XA not supported\n");
- CdromData->XaFlags |= XA_NOT_SUPPORTED;
- }
- }
- else
- {
- DPRINT("Use 6 byte commands\n");
- }
-
- /* Read 'capabilities & mechanical status page' to get additional drive capabilities */
- Length = sizeof(MODE_READ_RECOVERY_PAGE) + MODE_HEADER_LENGTH;
-
- if (!(CdromData->XaFlags & XA_NOT_SUPPORTED))
- {
- RtlZeroMemory (&Srb, sizeof(SCSI_REQUEST_BLOCK));
- Srb.TimeOutValue = DiskDeviceExtension->TimeOutValue;
- Cdb = (PCDB)Srb.Cdb;
-
- if (CdromData->XaFlags & XA_USE_10_BYTE)
- {
- /* Try the 10 byte version */
- Length = sizeof(MODE_CAPABILITIES_PAGE2) + MODE_HEADER_LENGTH10;
-
- Srb.CdbLength = 10;
- Cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
- Cdb->MODE_SENSE10.PageCode = 0x2a;
- Cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(Length >> 8);
- Cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(Length & 0xFF);
- }
- else
- {
- Length = sizeof(MODE_CAPABILITIES_PAGE2) + MODE_HEADER_LENGTH;
-
- Srb.CdbLength = 6;
- Cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
- Cdb->MODE_SENSE.PageCode = 0x2a;
- Cdb->MODE_SENSE.AllocationLength = (UCHAR)Length;
- }
- Status = ScsiClassSendSrbSynchronous (DiskDeviceObject,
- &Srb,
- Buffer,
- Length,
- FALSE);
- if (NT_SUCCESS (Status))
- {
-#if 0
- PMODE_CAPABILITIES_PAGE2 CapabilitiesData;
- if (CdromData->XaFlags & XA_USE_10_BYTE)
- {
- CapabilitiesData = (PMODE_CAPABILITIES_PAGE2)(Buffer + sizeof(MODE_PARAMETER_HEADER10));
- }
- else
- {
- CapabilitiesData = (PMODE_CAPABILITIES_PAGE2)(Buffer + sizeof(MODE_PARAMETER_HEADER));
- }
-
- DbgPrint("Capabilities for '%s':\n", NameBuffer);
- if (CapabilitiesData->Reserved2[0] & 0x20)
- {
- DbgPrint(" Drive supports reading of DVD-RAM discs\n");
- }
- if (CapabilitiesData->Reserved2[0] & 0x10)
- {
- DbgPrint(" Drive supports reading of DVD-R discs\n");
- }
- if (CapabilitiesData->Reserved2[0] & 0x08)
- {
- DbgPrint(" Drive supports reading of DVD-ROM discs\n");
- }
- if (CapabilitiesData->Reserved2[0] & 0x04)
- {
- DbgPrint(" Drive supports reading CD-R discs with addressing method 2\n");
- }
- if (CapabilitiesData->Reserved2[0] & 0x02)
- {
- DbgPrint(" Drive can read from CD-R/W (CD-E) discs (orange book, part III)\n");
- }
- if (CapabilitiesData->Reserved2[0] & 0x01)
- {
- DbgPrint(" Drive supports read from CD-R discs (orange book, part II)\n");
- }
- DPRINT("CapabilitiesData.Reserved2[1] %x\n", CapabilitiesData->Reserved2[1]);
- if (CapabilitiesData->Reserved2[1] & 0x01)
- {
- DbgPrint(" Drive can write to CD-R discs (orange book, part II)\n");
- }
- if (CapabilitiesData->Reserved2[1] & 0x02)
- {
- DbgPrint(" Drive can write to CD-R/W (CD-E) discs (orange book, part III)\n");
- }
- if (CapabilitiesData->Reserved2[1] & 0x04)
- {
- DbgPrint(" Drive can fake writes\n");
- }
- if (CapabilitiesData->Reserved2[1] & 0x10)
- {
- DbgPrint(" Drive can write DVD-R discs\n");
- }
- if (CapabilitiesData->Reserved2[1] & 0x20)
- {
- DbgPrint(" Drive can write DVD-RAM discs\n");
- }
- DPRINT("CapabilitiesData.Capabilities[0] %x\n", CapabilitiesData->Capabilities[0]);
- if (CapabilitiesData->Capabilities[0] & 0x01)
- {
- DbgPrint(" Drive supports audio play operations\n");
- }
- if (CapabilitiesData->Capabilities[0] & 0x02)
- {
- DbgPrint(" Drive can deliver a composite audio/video data stream\n");
- }
- if (CapabilitiesData->Capabilities[0] & 0x04)
- {
- DbgPrint(" Drive supports digital output on port 1\n");
- }
- if (CapabilitiesData->Capabilities[0] & 0x08)
- {
- DbgPrint(" Drive supports digital output on port 2\n");
- }
- if (CapabilitiesData->Capabilities[0] & 0x10)
- {
- DbgPrint(" Drive can read mode 2, form 1 (XA) data\n");
- }
- if (CapabilitiesData->Capabilities[0] & 0x20)
- {
- DbgPrint(" Drive can read mode 2, form 2 data\n");
- }
- if (CapabilitiesData->Capabilities[0] & 0x40)
- {
- DbgPrint(" Drive can read multisession discs\n");
- }
- DPRINT("CapabilitiesData.Capabilities[1] %x\n", CapabilitiesData->Capabilities[1]);
- if (CapabilitiesData->Capabilities[1] & 0x01)
- {
- DbgPrint(" Drive can read Red Book audio data\n");
- }
- if (CapabilitiesData->Capabilities[1] & 0x02)
- {
- DbgPrint(" Drive can continue a read cdda operation from a loss of streaming\n");
- }
- if (CapabilitiesData->Capabilities[1] & 0x04)
- {
- DbgPrint(" Subchannel reads can return combined R-W information\n");
- }
- if (CapabilitiesData->Capabilities[1] & 0x08)
- {
- DbgPrint(" R-W data will be returned deinterleaved and error corrected\n");
- }
- if (CapabilitiesData->Capabilities[1] & 0x10)
- {
- DbgPrint(" Drive supports C2 error pointers\n");
- }
- if (CapabilitiesData->Capabilities[1] & 0x20)
- {
- DbgPrint(" Drive can return International Standard Recording Code info\n");
- }
- if (CapabilitiesData->Capabilities[1] & 0x40)
- {
- DbgPrint(" Drive can return Media Catalog Number (UPC) info\n");
- }
- DPRINT("CapabilitiesData.Capabilities[2] %x\n", CapabilitiesData->Capabilities[2]);
- if (CapabilitiesData->Capabilities[2] & 0x01)
- {
- DbgPrint(" Drive can lock the door\n");
- }
- if (CapabilitiesData->Capabilities[2] & 0x02)
- {
- DbgPrint(" The door is locked\n");
- }
- if (CapabilitiesData->Capabilities[2] & 0x04)
- {
- }
- if (CapabilitiesData->Capabilities[2] & 0x08)
- {
- DbgPrint(" Drive can eject a disc or changer cartridge\n");
- }
- if (CapabilitiesData->Capabilities[2] & 0x10)
- {
- DbgPrint(" Drive supports C2 error pointers\n");
- }
- switch (CapabilitiesData->Capabilities[2] >> 5)
- {
- case 0:
- DbgPrint(" Drive use a caddy type loading mechanism\n");
- break;
- case 1:
- DbgPrint(" Drive use a tray type loading mechanism\n");
- break;
- case 2:
- DbgPrint(" Drive use a pop-up type loading mechanism\n");
- break;
- case 4:
- DbgPrint(" Drive is a changer with individually changeable discs\n");
- break;
- case 5:
- DbgPrint(" Drive is a changer with cartridge mechanism\n");
- break;
- }
- DPRINT("CapabilitiesData.Capabilities[3] %x\n", CapabilitiesData->Capabilities[3]);
- if (CapabilitiesData->Capabilities[3] & 0x01)
- {
- DbgPrint(" Audio level for each channel can be controlled independently\n");
- }
- if (CapabilitiesData->Capabilities[3] & 0x02)
- {
- DbgPrint(" Audio for each channel can be muted independently\n");
- }
- if (CapabilitiesData->Capabilities[3] & 0x04)
- {
- DbgPrint(" Changer can report exact contents of slots\n");
- }
- if (CapabilitiesData->Capabilities[3] & 0x08)
- {
- DbgPrint(" Drive supports software slot selection\n");
- }
- DbgPrint(" Maximum speed is %d kB/s\n",
- (CapabilitiesData->MaximumSpeedSupported[0] << 8)
- | CapabilitiesData->MaximumSpeedSupported[1]);
- DbgPrint(" Current speed is %d kB/s\n",
- (CapabilitiesData->CurrentSpeed[0] << 8)
- | CapabilitiesData->CurrentSpeed[1]);
- DbgPrint(" Number of discrete volume levels is %d\n",
- (CapabilitiesData->Reserved3 << 8)
- | CapabilitiesData->NumberVolumeLevels);
- DbgPrint(" Buffer size is %d kB\n",
- (CapabilitiesData->BufferSize[0] << 8)
- | CapabilitiesData->BufferSize[1]);
-#endif
- }
- else
- {
- DPRINT("XA not supported\n");
- CdromData->XaFlags |= XA_NOT_SUPPORTED;
- }
+#define ITEMS_TO_QUERY 2 /* always 1 greater than what is searched */
+ PRTL_QUERY_REGISTRY_TABLE parameters = NULL;
+ NTSTATUS status;
+ LONG zero = 0;
+
+ LONG tmp = 0;
+ LONG doRun = 0;
+
+ UCHAR buf[32];
+ ANSI_STRING paramNum;
+ UNICODE_STRING paramStr;
+
+ UNICODE_STRING paramSuffix;
+ UNICODE_STRING paramPath;
+ UNICODE_STRING paramDevPath;
+
+ //
+ // First append \Parameters to the passed in registry path
+ //
+
+ RtlInitUnicodeString(¶mStr, L"\\Parameters");
+
+ RtlInitUnicodeString(¶mPath, NULL);
+
+ paramPath.MaximumLength = RegistryPath->Length +
+ paramStr.Length +
+ sizeof(WCHAR);
+
+ paramPath.Buffer = ExAllocatePool(PagedPool, paramPath.MaximumLength);
+
+ if(!paramPath.Buffer) {
+
+ DebugPrint((1,"CdRomCheckRegAP: couldn't allocate paramPath\n"));
+
+ return FALSE;
}
+ RtlZeroMemory(paramPath.Buffer, paramPath.MaximumLength);
+ RtlAppendUnicodeToString(¶mPath, RegistryPath->Buffer);
+ RtlAppendUnicodeToString(¶mPath, paramStr.Buffer);
- ExFreePool (Buffer);
+ DebugPrint((2, "CdRomCheckRegAP: paramPath [%d] = %ws\n",
+ paramPath.Length,
+ paramPath.Buffer));
- /* Initialize device timer */
- IoInitializeTimer(DiskDeviceObject,
- CdromTimerRoutine,
- NULL);
- IoStartTimer(DiskDeviceObject);
+ //
+ // build a counted ANSI string that contains
+ // the suffix for the path
+ //
- DiskDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
+ sprintf(buf, "\\Device%d", DeviceNumber);
+ RtlInitAnsiString(¶mNum, buf);
- DPRINT("CdromClassCreateDeviceObjects() done\n");
+ //
+ // Next convert this into a unicode string
+ //
- return(STATUS_SUCCESS);
-}
+ status = RtlAnsiStringToUnicodeString(¶mSuffix, ¶mNum, TRUE);
+ if(!NT_SUCCESS(status)) {
+ DebugPrint((1,"CdRomCheckRegAP: couldn't convert paramNum to paramSuffix\n"));
+ ExFreePool(paramPath.Buffer);
+ return FALSE;
+ }
-/**********************************************************************
- * NAME
- * CdromClassReadTocEntry
- *
- * ARGUMENTS:
- * DeviceObject
- * TrackNo
- * Buffer
- * Length
- *
- * RETURNS:
- * Status.
- */
-static NTSTATUS
-CdromClassReadTocEntry (PDEVICE_OBJECT DeviceObject,
- SIZE_T TrackNo,
- PVOID Buffer,
- SIZE_T Length)
-{
- PDEVICE_EXTENSION DeviceExtension;
- SCSI_REQUEST_BLOCK Srb;
- PCDB Cdb;
-
- DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
-
- RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
- Srb.CdbLength = 10;
- Srb.TimeOutValue = DeviceExtension->TimeOutValue;
-
- Cdb = (PCDB)Srb.Cdb;
- Cdb->READ_TOC.OperationCode = SCSIOP_READ_TOC;
- Cdb->READ_TOC.StartingTrack = TrackNo;
- Cdb->READ_TOC.Format = 0;
- Cdb->READ_TOC.AllocationLength[0] = Length >> 8;
- Cdb->READ_TOC.AllocationLength[1] = Length & 0xff;
- Cdb->READ_TOC.Msf = 1;
-
- return(ScsiClassSendSrbSynchronous(DeviceObject,
- &Srb,
- Buffer,
- Length,
- FALSE));
-}
+ RtlInitUnicodeString(¶mDevPath, NULL);
+ //
+ // now build the device specific path
+ //
-static NTSTATUS
-CdromClassReadLastSession (PDEVICE_OBJECT DeviceObject,
- SIZE_T TrackNo,
- PVOID Buffer,
- SIZE_T Length)
-{
- PDEVICE_EXTENSION DeviceExtension;
- SCSI_REQUEST_BLOCK Srb;
- PCDB Cdb;
-
- DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
-
- RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
- Srb.CdbLength = 10;
- Srb.TimeOutValue = DeviceExtension->TimeOutValue;
-
- Cdb = (PCDB)Srb.Cdb;
- Cdb->READ_TOC.OperationCode = SCSIOP_READ_TOC;
- Cdb->READ_TOC.StartingTrack = TrackNo;
- Cdb->READ_TOC.Format = 1;
- Cdb->READ_TOC.AllocationLength[0] = Length >> 8;
- Cdb->READ_TOC.AllocationLength[1] = Length & 0xff;
- Cdb->READ_TOC.Msf = 0;
-
- return(ScsiClassSendSrbSynchronous(DeviceObject,
- &Srb,
- Buffer,
- Length,
- FALSE));
+ paramDevPath.MaximumLength = paramPath.Length +
+ paramSuffix.Length +
+ sizeof(WCHAR);
+ paramDevPath.Buffer = ExAllocatePool(PagedPool, paramDevPath.MaximumLength);
+
+ if(!paramDevPath.Buffer) {
+ RtlFreeUnicodeString(¶mSuffix);
+ ExFreePool(paramPath.Buffer);
+ return FALSE;
+ }
+
+ RtlZeroMemory(paramDevPath.Buffer, paramDevPath.MaximumLength);
+ RtlAppendUnicodeToString(¶mDevPath, paramPath.Buffer);
+ RtlAppendUnicodeToString(¶mDevPath, paramSuffix.Buffer);
+
+ DebugPrint((2, "CdRomCheckRegAP: paramDevPath [%d] = %ws\n",
+ paramPath.Length,
+ paramPath.Buffer));
+
+ parameters = ExAllocatePool(NonPagedPool,
+ sizeof(RTL_QUERY_REGISTRY_TABLE)*ITEMS_TO_QUERY);
+
+ if (parameters) {
+
+ //
+ // Check for the Autorun value.
+ //
+
+ RtlZeroMemory(parameters,
+ (sizeof(RTL_QUERY_REGISTRY_TABLE)*ITEMS_TO_QUERY));
+
+ parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ parameters[0].Name = L"Autorun";
+ parameters[0].EntryContext = &doRun;
+ parameters[0].DefaultType = REG_DWORD;
+ parameters[0].DefaultData = &zero;
+ parameters[0].DefaultLength = sizeof(ULONG);
+
+ status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
+ RegistryPath->Buffer,
+ parameters,
+ NULL,
+ NULL);
+
+ DebugPrint((2, "CdRomCheckRegAP: cdrom/Autorun flag = %d\n", doRun));
+
+ RtlZeroMemory(parameters,
+ (sizeof(RTL_QUERY_REGISTRY_TABLE)*ITEMS_TO_QUERY));
+
+ parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ parameters[0].Name = L"Autorun";
+ parameters[0].EntryContext = &tmp;
+ parameters[0].DefaultType = REG_DWORD;
+ parameters[0].DefaultData = &doRun;
+ parameters[0].DefaultLength = sizeof(ULONG);
+
+ status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
+ paramPath.Buffer,
+ parameters,
+ NULL,
+ NULL);
+
+ DebugPrint((2, "CdRomCheckRegAP: cdrom/parameters/autorun flag = %d\n", tmp));
+
+ RtlZeroMemory(parameters,
+ (sizeof(RTL_QUERY_REGISTRY_TABLE) * ITEMS_TO_QUERY));
+
+ parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ parameters[0].Name = L"Autorun";
+ parameters[0].EntryContext = &doRun;
+ parameters[0].DefaultType = REG_DWORD;
+ parameters[0].DefaultData = &tmp;
+ parameters[0].DefaultLength = sizeof(ULONG);
+
+ status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
+ paramDevPath.Buffer,
+ parameters,
+ NULL,
+ NULL);
+
+ DebugPrint((1, "CdRomCheckRegAP: cdrom/parameters/device%d/autorun flag = %d\n", DeviceNumber, doRun));
+
+ ExFreePool(parameters);
+
+ }
+
+ ExFreePool(paramPath.Buffer);
+ ExFreePool(paramDevPath.Buffer);
+ RtlFreeUnicodeString(¶mSuffix);
+
+ DebugPrint((1, "CdRomCheckRegAP: Autoplay for device %d is %s\n",
+ DeviceNumber,
+ (doRun ? "on" : "off")));
+
+ if(doRun) {
+ return TRUE;
+ }
+
+ return FALSE;
}
+\f
+BOOLEAN
+STDCALL
+IsThisASanyo(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN UCHAR PathId,
+ IN UCHAR TargetId
+ )
-/**********************************************************************
- * NAME EXPORTED
- * CdromClassDeviceControl
- *
- * DESCRIPTION:
- * Answer requests for device control calls
- *
- * RUN LEVEL:
- * PASSIVE_LEVEL
- *
- * ARGUMENTS:
- * DeviceObject
- * Irp
- * Standard dispatch arguments
- *
- * RETURNS:
- * Status.
- */
+/*++
+
+Routine Description:
+
+ This routine is called by DriverEntry to determine whether a Sanyo 3-CD
+ changer device is present.
+
+Arguments:
+
+ DeviceObject - Supplies the device object for the 'real' device.
+
+ PathId -
+
+Return Value:
+
+ TRUE - if an Atapi changer device is found.
+
+--*/
-NTSTATUS STDCALL
-CdromClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp)
{
- PDEVICE_EXTENSION DeviceExtension;
- PIO_STACK_LOCATION IrpStack;
- ULONG ControlCode, InputLength, OutputLength;
- PCDROM_DATA CdromData;
- ULONG Information;
- NTSTATUS Status;
-
- DPRINT("CdromClassDeviceControl() called!\n");
-
- Status = STATUS_INVALID_DEVICE_REQUEST;
- Information = 0;
- IrpStack = IoGetCurrentIrpStackLocation(Irp);
- ControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
- InputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
- OutputLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
- DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
- CdromData = (PCDROM_DATA)(DeviceExtension + 1);
-
- switch (ControlCode)
- {
- case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
- DPRINT ("CdromClassDeviceControl: IOCTL_CDROM_GET_DRIVE_GEOMETRY\n");
- if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY))
- {
- Status = STATUS_INFO_LENGTH_MISMATCH;
- break;
- }
- IoMarkIrpPending (Irp);
- IoStartPacket (DeviceObject,
- Irp,
- NULL,
- NULL);
- return STATUS_PENDING;
-
- case IOCTL_CDROM_CHECK_VERIFY:
- DPRINT ("CdromClassDeviceControl: IOCTL_CDROM_CHECK_VERIFY\n");
- if (OutputLength != 0 && OutputLength < sizeof (ULONG))
- {
- DPRINT1("Buffer too small\n");
- Status = STATUS_BUFFER_TOO_SMALL;
- break;
- }
- IoMarkIrpPending (Irp);
- IoStartPacket (DeviceObject,
- Irp,
- NULL,
- NULL);
- return STATUS_PENDING;
-
- case IOCTL_CDROM_READ_TOC:
- DPRINT("IOCTL_CDROM_READ_TOC\n");
- if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(CDROM_TOC))
- {
- Status = STATUS_INFO_LENGTH_MISMATCH;
- }
- else
- {
- PCDROM_TOC TocBuffer;
- USHORT Length;
-
- TocBuffer = Irp->AssociatedIrp.SystemBuffer;
-
- /* First read the lead out */
- Length = 4 + sizeof(TRACK_DATA);
- Status = CdromClassReadTocEntry(DeviceObject,
- 0xAA,
- TocBuffer,
- Length);
- if (NT_SUCCESS(Status))
- {
- if (TocBuffer->FirstTrack == 0xaa)
- {
- /* there is an empty cd */
- Information = Length;
- }
- else
- {
- /* read the toc */
- Length = 4 + sizeof(TRACK_DATA) * (TocBuffer->LastTrack - TocBuffer->FirstTrack + 2);
- Status = CdromClassReadTocEntry(DeviceObject,
- TocBuffer->FirstTrack,
- TocBuffer, Length);
- if (NT_SUCCESS(Status))
- {
- Information = Length;
- }
- }
- }
- }
- break;
-
- case IOCTL_CDROM_GET_LAST_SESSION:
- DPRINT("IOCTL_CDROM_GET_LAST_SESSION\n");
- if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < 4 + sizeof(TRACK_DATA))
- {
- Status = STATUS_INFO_LENGTH_MISMATCH;
- }
- else
- {
- PCDROM_TOC TocBuffer;
- USHORT Length;
-
- TocBuffer = Irp->AssociatedIrp.SystemBuffer;
- Length = 4 + sizeof(TRACK_DATA);
- Status = CdromClassReadLastSession(DeviceObject,
- 0,
- TocBuffer,
- Length);
- if (NT_SUCCESS(Status))
- {
- Information = Length;
- }
- }
- break;
-
- default:
- /* Call the common device control function */
- return(ScsiClassDeviceControl(DeviceObject, Irp));
- }
-
- /* Verify the device if the user caused the error */
- if (!NT_SUCCESS(Status) && IoIsErrorUserInduced(Status))
- {
- IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
- }
-
- Irp->IoStatus.Status = Status;
- Irp->IoStatus.Information = Information;
- IoCompleteRequest(Irp,
- IO_DISK_INCREMENT);
-
- return Status;
+ KEVENT event;
+ PIRP irp;
+ PCHAR inquiryBuffer;
+ IO_STATUS_BLOCK ioStatus;
+ NTSTATUS status;
+ PSCSI_ADAPTER_BUS_INFO adapterInfo;
+ ULONG scsiBus;
+ PINQUIRYDATA inquiryData;
+ PSCSI_INQUIRY_DATA lunInfo;
+
+ inquiryBuffer = ExAllocatePool(NonPagedPool, 2048);
+ KeInitializeEvent(&event, NotificationEvent, FALSE);
+ irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA,
+ DeviceObject,
+ NULL,
+ 0,
+ inquiryBuffer,
+ 2048,
+ FALSE,
+ &event,
+ &ioStatus);
+ if (!irp) {
+ return FALSE;
+ }
+
+ status = IoCallDriver(DeviceObject, irp);
+
+ if (status == STATUS_PENDING) {
+ KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
+ status = ioStatus.Status;
+ }
+
+ if (!NT_SUCCESS(status)) {
+ return FALSE;
+ }
+
+ adapterInfo = (PVOID) inquiryBuffer;
+
+ for (scsiBus=0; scsiBus < (ULONG)adapterInfo->NumberOfBuses; scsiBus++) {
+
+ //
+ // Get the SCSI bus scan data for this bus.
+ //
+
+ lunInfo = (PVOID) (inquiryBuffer + adapterInfo->BusData[scsiBus].InquiryDataOffset);
+
+ for (;;) {
+
+ if (lunInfo->PathId == PathId && lunInfo->TargetId == TargetId) {
+
+ inquiryData = (PVOID) lunInfo->InquiryData;
+
+ if (RtlCompareMemory(inquiryData->VendorId, "TORiSAN CD-ROM CDR-C", 20) == 20) {
+ ExFreePool(inquiryBuffer);
+ return TRUE;
+ }
+
+ ExFreePool(inquiryBuffer);
+ return FALSE;
+ }
+
+ if (!lunInfo->NextInquiryDataOffset) {
+ break;
+ }
+
+ lunInfo = (PVOID) (inquiryBuffer + lunInfo->NextInquiryDataOffset);
+ }
+ }
+
+ ExFreePool(inquiryBuffer);
+ return FALSE;
}
+\f
+BOOLEAN
+STDCALL
+IsThisAnAtapiChanger(
+ IN PDEVICE_OBJECT DeviceObject,
+ OUT PULONG DiscsPresent
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by DriverEntry to determine whether an Atapi
+ changer device is present.
+
+Arguments:
+
+ DeviceObject - Supplies the device object for the 'real' device.
+
+ DiscsPresent - Supplies a pointer to the number of Discs supported by the changer.
+
+Return Value:
+
+ TRUE - if an Atapi changer device is found.
+
+--*/
-/**********************************************************************
- * NAME
- * CdromClassStartIo
- *
- * DESCRIPTION:
- * Starts IRP processing.
- *
- * RUN LEVEL:
- * PASSIVE_LEVEL
- *
- * ARGUMENTS:
- * DeviceObject
- * Irp
- * Standard dispatch arguments
- *
- * RETURNS:
- * None.
- */
-VOID STDCALL
-CdromClassStartIo (IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp)
{
- PDEVICE_EXTENSION DeviceExtension;
- PIO_STACK_LOCATION IrpStack;
- PIO_STACK_LOCATION SubIrpStack;
- ULONG MaximumTransferLength;
- ULONG TransferPages;
- PSCSI_REQUEST_BLOCK Srb;
- PIRP SubIrp;
- PUCHAR SenseBuffer;
- PVOID DataBuffer;
- PCDB Cdb;
-
- DPRINT("CdromClassStartIo() called!\n");
-
- IoMarkIrpPending (Irp);
-
- DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
- IrpStack = IoGetCurrentIrpStackLocation (Irp);
-
- MaximumTransferLength = DeviceExtension->PortCapabilities->MaximumTransferLength;
-
- if (DeviceObject->Flags & DO_VERIFY_VOLUME)
- {
- if (!(IrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME))
- {
- DPRINT1 ("Verify required\n");
-
- if (Irp->Tail.Overlay.Thread)
- {
- IoSetHardErrorOrVerifyDevice (Irp,
- DeviceObject);
- }
- Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
-
- /* FIXME: Update drive capacity */
- IoCompleteRequest (Irp,
- IO_DISK_INCREMENT);
- IoStartNextPacket (DeviceObject,
- FALSE);
- return;
- }
- }
-
- if (IrpStack->MajorFunction == IRP_MJ_READ)
- {
- DPRINT ("CdromClassStartIo: IRP_MJ_READ\n");
-
- TransferPages =
- ADDRESS_AND_SIZE_TO_SPAN_PAGES (MmGetMdlVirtualAddress(Irp->MdlAddress),
- IrpStack->Parameters.Read.Length);
-
- /* Check transfer size */
- if ((IrpStack->Parameters.Read.Length > MaximumTransferLength) ||
- (TransferPages > DeviceExtension->PortCapabilities->MaximumPhysicalPages))
- {
- /* Transfer size is too large - split it */
- TransferPages =
- DeviceExtension->PortCapabilities->MaximumPhysicalPages - 1;
-
- /* Adjust transfer size */
- if (MaximumTransferLength > TransferPages * PAGE_SIZE)
- MaximumTransferLength = TransferPages * PAGE_SIZE;
-
- if (MaximumTransferLength == 0)
- MaximumTransferLength = PAGE_SIZE;
-
- /* Split the transfer */
- ScsiClassSplitRequest (DeviceObject,
- Irp,
- MaximumTransferLength);
- return;
- }
- else
- {
- /* Build SRB */
- ScsiClassBuildRequest (DeviceObject,
- Irp);
- }
- }
- else if (IrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL)
- {
- DPRINT ("CdromClassStartIo: IRP_MJ_IRP_MJ_DEVICE_CONTROL\n");
-
- /* Allocate an IRP for sending requests to the port driver */
- SubIrp = IoAllocateIrp ((CCHAR)(DeviceObject->StackSize + 1),
- FALSE);
- if (SubIrp == NULL)
- {
- Irp->IoStatus.Information = 0;
- Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
- IoCompleteRequest (Irp,
- IO_DISK_INCREMENT);
- IoStartNextPacket (DeviceObject,
- FALSE);
- return;
- }
-
- /* Allocate an SRB */
- Srb = ExAllocatePool (NonPagedPool,
- sizeof (SCSI_REQUEST_BLOCK));
- if (Srb == NULL)
- {
- IoFreeIrp (SubIrp);
- Irp->IoStatus.Information = 0;
- Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
- IoCompleteRequest (Irp,
- IO_DISK_INCREMENT);
- IoStartNextPacket (DeviceObject,
- FALSE);
- return;
- }
-
- /* Allocte a sense buffer */
- SenseBuffer = ExAllocatePool (NonPagedPoolCacheAligned,
- SENSE_BUFFER_SIZE);
- if (SenseBuffer == NULL)
- {
- ExFreePool (Srb);
- IoFreeIrp (SubIrp);
- Irp->IoStatus.Information = 0;
- Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
- IoCompleteRequest (Irp,
- IO_DISK_INCREMENT);
- IoStartNextPacket (DeviceObject,
- FALSE);
- return;
- }
-
- /* Initialize the IRP */
- IoSetNextIrpStackLocation (SubIrp);
- SubIrp->IoStatus.Information = 0;
- SubIrp->IoStatus.Status = STATUS_SUCCESS;
- SubIrp->Flags = 0;
- SubIrp->UserBuffer = NULL;
-
- SubIrpStack = IoGetCurrentIrpStackLocation (SubIrp);
- SubIrpStack->DeviceObject = DeviceExtension->DeviceObject;
- SubIrpStack->Parameters.Others.Argument2 = (PVOID)Irp;
-
- /* Initialize next stack location */
- SubIrpStack = IoGetNextIrpStackLocation (SubIrp);
- SubIrpStack->MajorFunction = IRP_MJ_SCSI;
- SubIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
- SubIrpStack->Parameters.Scsi.Srb = Srb;
-
- /* Initialize the SRB */
- RtlZeroMemory(Srb,
- sizeof (SCSI_REQUEST_BLOCK));
- Srb->Length = sizeof (SCSI_REQUEST_BLOCK);
- Srb->PathId = DeviceExtension->PathId;
- Srb->TargetId = DeviceExtension->TargetId;
- Srb->Lun = DeviceExtension->Lun;
- Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
- Srb->SrbStatus = SRB_STATUS_SUCCESS;
- Srb->ScsiStatus = 0;
- Srb->NextSrb = 0;
- Srb->OriginalRequest = SubIrp;
- Srb->SenseInfoBuffer = SenseBuffer;
- Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
-
- /* Initialize the CDB */
- Cdb = (PCDB)Srb->Cdb;
-
- /* Set the completion routine */
- IoSetCompletionRoutine (SubIrp,
- CdromDeviceControlCompletion,
- Srb,
- TRUE,
- TRUE,
- TRUE);
-
- switch (IrpStack->Parameters.DeviceIoControl.IoControlCode)
- {
- case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
- DPRINT ("CdromClassStartIo: IOCTL_CDROM_GET_DRIVE_GEOMETRY\n");
- Srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
- Srb->CdbLength = 10;
- Srb->TimeOutValue = DeviceExtension->TimeOutValue;
- Srb->SrbFlags = SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN;
- Cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
-
- /* Allocate data buffer */
- DataBuffer = ExAllocatePool (NonPagedPoolCacheAligned,
- sizeof(READ_CAPACITY_DATA));
- if (DataBuffer == NULL)
- {
- Irp->IoStatus.Information = 0;
- Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
- IoCompleteRequest (Irp,
- IO_DISK_INCREMENT);
- ExFreePool (SenseBuffer);
- ExFreePool (Srb);
- IoFreeIrp (SubIrp);
- IoStartNextPacket (DeviceObject,
- FALSE);
- return;
- }
-
- /* Allocate an MDL for the data buffer */
- SubIrp->MdlAddress = IoAllocateMdl (DataBuffer,
- sizeof(READ_CAPACITY_DATA),
- FALSE,
- FALSE,
- NULL);
- if (SubIrp->MdlAddress == NULL)
- {
- Irp->IoStatus.Information = 0;
- Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
- IoCompleteRequest (Irp,
- IO_DISK_INCREMENT);
- ExFreePool (DataBuffer);
- ExFreePool (SenseBuffer);
- ExFreePool (Srb);
- IoFreeIrp (SubIrp);
- IoStartNextPacket (DeviceObject,
- FALSE);
- return;
- }
-
- MmBuildMdlForNonPagedPool (SubIrp->MdlAddress);
- Srb->DataBuffer = DataBuffer;
-
- RtlZeroMemory(DataBuffer, sizeof(READ_CAPACITY_DATA));
- IoCallDriver (DeviceExtension->PortDeviceObject,
- SubIrp);
- return;
-
- case IOCTL_CDROM_CHECK_VERIFY:
- DPRINT ("CdromClassStartIo: IOCTL_CDROM_CHECK_VERIFY\n");
- Srb->CdbLength = 6;
- Srb->TimeOutValue = DeviceExtension->TimeOutValue * 2;
- Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
- Cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
-
- IoCallDriver (DeviceExtension->PortDeviceObject,
- SubIrp);
- return;
-
- default:
- IoCompleteRequest (Irp,
- IO_NO_INCREMENT);
- return;
- }
- }
-
- /* Call the SCSI port driver */
- IoCallDriver (DeviceExtension->PortDeviceObject,
- Irp);
+ PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
+ PMECHANICAL_STATUS_INFORMATION_HEADER mechanicalStatusBuffer;
+ NTSTATUS status;
+ SCSI_REQUEST_BLOCK srb;
+ PCDB cdb = (PCDB) &srb.Cdb[0];
+ BOOLEAN retVal = FALSE;
+
+ *DiscsPresent = 0;
+
+ //
+ // Some devices can't handle 12 byte CDB's gracefully
+ //
+
+ if(deviceExtension->DeviceFlags & DEV_NO_12BYTE_CDB) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Build and issue the mechanical status command.
+ //
+
+ mechanicalStatusBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
+ sizeof(MECHANICAL_STATUS_INFORMATION_HEADER));
+
+ if (!mechanicalStatusBuffer) {
+ retVal = FALSE;
+ } else {
+
+ //
+ // Build and send the Mechanism status CDB.
+ //
+
+ RtlZeroMemory(&srb, sizeof(srb));
+
+ srb.CdbLength = 12;
+ srb.TimeOutValue = 20;
+
+ cdb->MECH_STATUS.OperationCode = SCSIOP_MECHANISM_STATUS;
+ cdb->MECH_STATUS.AllocationLength[1] = sizeof(MECHANICAL_STATUS_INFORMATION_HEADER);
+
+ status = ScsiClassSendSrbSynchronous(DeviceObject,
+ &srb,
+ mechanicalStatusBuffer,
+ sizeof(MECHANICAL_STATUS_INFORMATION_HEADER),
+ FALSE);
+
+
+ if (status == STATUS_SUCCESS) {
+
+ //
+ // Indicate number of slots available
+ //
+
+ *DiscsPresent = mechanicalStatusBuffer->NumberAvailableSlots;
+ if (*DiscsPresent > 1) {
+ retVal = TRUE;
+ } else {
+
+ //
+ // If only one disc, no need for this driver.
+ //
+
+ retVal = FALSE;
+ }
+ } else {
+
+ //
+ // Device doesn't support this command.
+ //
+
+ retVal = FALSE;
+ }
+
+ ExFreePool(mechanicalStatusBuffer);
+ }
+
+ return retVal;
}
+\f
+BOOLEAN
+STDCALL
+IsThisAMultiLunDevice(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PDEVICE_OBJECT PortDeviceObject
+ )
+/*++
+
+Routine Description:
+
+ This routine is called to determine whether a multi-lun
+ device is present.
+
+Arguments:
+
+ DeviceObject - Supplies the device object for the 'real' device.
+
+Return Value:
-NTSTATUS STDCALL
-CdromDeviceControlCompletion (IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp,
- IN PVOID Context)
+ TRUE - if a Multi-lun device is found.
+
+--*/
{
- PDEVICE_EXTENSION DeviceExtension;
- PDEVICE_EXTENSION PhysicalExtension;
- PIO_STACK_LOCATION IrpStack;
- PIO_STACK_LOCATION OrigCurrentIrpStack;
- PIO_STACK_LOCATION OrigNextIrpStack;
- PSCSI_REQUEST_BLOCK Srb;
- PIRP OrigIrp;
- BOOLEAN Retry;
- NTSTATUS Status;
-
- DPRINT ("CdromDeviceControlCompletion() called\n");
-
- DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
- PhysicalExtension = (PDEVICE_EXTENSION)DeviceExtension->PhysicalDevice->DeviceExtension;
- Srb = (PSCSI_REQUEST_BLOCK) Context;
-
- IrpStack = IoGetCurrentIrpStackLocation (Irp);
-
- /* Get the original IRP */
- OrigIrp = (PIRP)IrpStack->Parameters.Others.Argument2;
- OrigCurrentIrpStack = IoGetCurrentIrpStackLocation (OrigIrp);
- OrigNextIrpStack = IoGetNextIrpStackLocation (OrigIrp);
-
- if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS)
- {
- Status = STATUS_SUCCESS;
- }
- else
- {
- DPRINT ("SrbStatus %lx\n", Srb->SrbStatus);
-
- /* Interpret sense info */
- Retry = ScsiClassInterpretSenseInfo (DeviceObject,
- Srb,
- IrpStack->MajorFunction,
- IrpStack->Parameters.DeviceIoControl.IoControlCode,
- MAXIMUM_RETRIES - (ULONG)OrigNextIrpStack->Parameters.Others.Argument1,
- &Status);
- DPRINT ("Retry %u\n", Retry);
-
- if (Retry == TRUE &&
- (ULONG)OrigNextIrpStack->Parameters.Others.Argument1 > 0)
- {
- DPRINT1 ("Try again (Retry count 0x%p)\n",
- (ULONG)OrigNextIrpStack->Parameters.Others.Argument1);
-
- OrigNextIrpStack->Parameters.Others.Argument1 = (PVOID)((ULONG_PTR)OrigNextIrpStack->Parameters.Others.Argument1 - 1);
-
- /* Release 'old' buffers */
- ExFreePool (Srb->SenseInfoBuffer);
- if (Srb->DataBuffer)
- ExFreePool(Srb->DataBuffer);
- ExFreePool(Srb);
-
- if (Irp->MdlAddress != NULL)
- IoFreeMdl(Irp->MdlAddress);
-
- IoFreeIrp(Irp);
-
- /* Call the StartIo routine again */
- CdromClassStartIo (DeviceObject,
- OrigIrp);
-
- return STATUS_MORE_PROCESSING_REQUIRED;
- }
-
- DPRINT ("Status %lx\n", Status);
- }
-
- if (NT_SUCCESS (Status))
- {
- switch (OrigCurrentIrpStack->Parameters.DeviceIoControl.IoControlCode)
- {
- case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
- {
- PREAD_CAPACITY_DATA CapacityBuffer;
- ULONG LastSector;
- ULONG SectorSize;
-
- DPRINT ("CdromClassControlCompletion: IOCTL_CDROM_GET_DRIVE_GEOMETRY\n");
-
- CapacityBuffer = (PREAD_CAPACITY_DATA)Srb->DataBuffer;
- SectorSize = (((PUCHAR)&CapacityBuffer->BytesPerBlock)[0] << 24) |
- (((PUCHAR)&CapacityBuffer->BytesPerBlock)[1] << 16) |
- (((PUCHAR)&CapacityBuffer->BytesPerBlock)[2] << 8) |
- ((PUCHAR)&CapacityBuffer->BytesPerBlock)[3];
-
- LastSector = (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[0] << 24) |
- (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[1] << 16) |
- (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[2] << 8) |
- ((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[3];
-
- if (SectorSize == 0)
- SectorSize = 2048;
- DeviceExtension->DiskGeometry->BytesPerSector = SectorSize;
-
- DeviceExtension->PartitionLength.QuadPart = (LONGLONG)(LastSector + 1);
- WHICH_BIT(DeviceExtension->DiskGeometry->BytesPerSector,
- DeviceExtension->SectorShift);
- DeviceExtension->PartitionLength.QuadPart =
- (DeviceExtension->PartitionLength.QuadPart << DeviceExtension->SectorShift);
-
- if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
- {
- DeviceExtension->DiskGeometry->MediaType = RemovableMedia;
- }
- else
- {
- DeviceExtension->DiskGeometry->MediaType = FixedMedia;
- }
- DeviceExtension->DiskGeometry->Cylinders.QuadPart =
- (LONGLONG)((LastSector + 1)/(32 * 64));
- DeviceExtension->DiskGeometry->SectorsPerTrack = 32;
- DeviceExtension->DiskGeometry->TracksPerCylinder = 64;
-
- RtlCopyMemory (OrigIrp->AssociatedIrp.SystemBuffer,
- DeviceExtension->DiskGeometry,
- sizeof(DISK_GEOMETRY));
- OrigIrp->IoStatus.Information = sizeof(DISK_GEOMETRY);
- }
- break;
-
- case IOCTL_CDROM_CHECK_VERIFY:
- DPRINT ("CdromDeviceControlCompletion: IOCTL_CDROM_CHECK_VERIFY\n");
- if (OrigCurrentIrpStack->Parameters.DeviceIoControl.OutputBufferLength != 0)
- {
- /* Return the media change counter */
- *((PULONG)(OrigIrp->AssociatedIrp.SystemBuffer)) =
- PhysicalExtension->MediaChangeCount;
- OrigIrp->IoStatus.Information = sizeof(ULONG);
- }
- else
- {
- OrigIrp->IoStatus.Information = 0;
- }
- break;
-
- default:
- OrigIrp->IoStatus.Information = 0;
- Status = STATUS_INVALID_DEVICE_REQUEST;
- break;
- }
- }
-
- /* Release the SRB and associated buffers */
- if (Srb != NULL)
- {
- DPRINT("Srb %p\n", Srb);
-
- if (Srb->DataBuffer != NULL)
- ExFreePool (Srb->DataBuffer);
-
- if (Srb->SenseInfoBuffer != NULL)
- ExFreePool (Srb->SenseInfoBuffer);
-
- ExFreePool (Srb);
- }
-
- if (OrigIrp->PendingReturned)
- {
- IoMarkIrpPending (OrigIrp);
- }
-
- /* Release the MDL */
- if (Irp->MdlAddress != NULL)
- {
- IoFreeMdl (Irp->MdlAddress);
- }
-
- /* Release the sub irp */
- IoFreeIrp (Irp);
-
- /* Set io status information */
- OrigIrp->IoStatus.Status = Status;
- if (!NT_SUCCESS(Status) && IoIsErrorUserInduced (Status))
- {
- IoSetHardErrorOrVerifyDevice (OrigIrp,
- DeviceObject);
- OrigIrp->IoStatus.Information = 0;
- }
-
- /* Complete the original IRP */
- IoCompleteRequest (OrigIrp,
- IO_DISK_INCREMENT);
- IoStartNextPacket (DeviceObject,
- FALSE);
-
- DPRINT ("CdromDeviceControlCompletion() done\n");
-
- return STATUS_MORE_PROCESSING_REQUIRED;
+ PCHAR buffer;
+ PSCSI_INQUIRY_DATA lunInfo;
+ PSCSI_ADAPTER_BUS_INFO adapterInfo;
+ PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+ PINQUIRYDATA inquiryData;
+ ULONG scsiBus;
+ NTSTATUS status;
+ UCHAR lunCount = 0;
+
+ status = ScsiClassGetInquiryData(PortDeviceObject, (PSCSI_ADAPTER_BUS_INFO *) &buffer);
+
+ if (!NT_SUCCESS(status)) {
+ DebugPrint((1,"IsThisAMultiLunDevice: ScsiClassGetInquiryData failed\n"));
+ return FALSE;
+ }
+
+ adapterInfo = (PVOID) buffer;
+
+ //
+ // For each SCSI bus this adapter supports ...
+ //
+
+ for (scsiBus=0; scsiBus < adapterInfo->NumberOfBuses; scsiBus++) {
+
+ //
+ // Get the SCSI bus scan data for this bus.
+ //
+
+ lunInfo = (PVOID) (buffer + adapterInfo->BusData[scsiBus].InquiryDataOffset);
+
+ while (adapterInfo->BusData[scsiBus].InquiryDataOffset) {
+
+ inquiryData = (PVOID)lunInfo->InquiryData;
+
+ if ((lunInfo->PathId == deviceExtension->PathId) &&
+ (lunInfo->TargetId == deviceExtension->TargetId) &&
+ (inquiryData->DeviceType == READ_ONLY_DIRECT_ACCESS_DEVICE)) {
+
+ DebugPrint((1,"IsThisAMultiLunDevice: Vendor string is %.24s\n",
+ inquiryData->VendorId));
+
+ //
+ // If this device has more than one cdrom-type lun then we
+ // won't support autoplay on it
+ //
+
+ if (lunCount++) {
+ ExFreePool(buffer);
+ return TRUE;
+ }
+ }
+
+ //
+ // Get next LunInfo.
+ //
+
+ if (lunInfo->NextInquiryDataOffset == 0) {
+ break;
+ }
+
+ lunInfo = (PVOID) (buffer + lunInfo->NextInquiryDataOffset);
+ }
+ }
+
+ ExFreePool(buffer);
+ return FALSE;
+
}
+\f
+NTSTATUS
+STDCALL
+CdRomUpdateGeometryCompletion(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp,
+ PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine andles the completion of the test unit ready irps
+ used to determine if the media has changed. If the media has
+ changed, this code signals the named event to wake up other
+ system services that react to media change (aka AutoPlay).
+
+Arguments:
+
+ DeviceObject - the object for the completion
+ Irp - the IRP being completed
+ Context - the SRB from the IRP
+
+Return Value:
+
+ NTSTATUS
+
+--*/
-VOID STDCALL
-CdromTimerRoutine(IN PDEVICE_OBJECT DeviceObject,
- IN PVOID Context)
{
- PIO_WORKITEM WorkItem;
+ PSCSI_REQUEST_BLOCK srb = (PSCSI_REQUEST_BLOCK) Context;
+ PREAD_CAPACITY_DATA readCapacityBuffer;
+ PDEVICE_EXTENSION deviceExtension;
+ PIO_STACK_LOCATION irpStack;
+ NTSTATUS status;
+ BOOLEAN retry;
+ ULONG retryCount;
+ ULONG lastSector;
+ PIRP originalIrp;
+ PCDROM_DATA cddata;
+
+ //
+ // Get items saved in the private IRP stack location.
+ //
+
+ irpStack = IoGetCurrentIrpStackLocation(Irp);
+ retryCount = (ULONG) irpStack->Parameters.Others.Argument1;
+ originalIrp = (PIRP) irpStack->Parameters.Others.Argument2;
+
+ if (!DeviceObject) {
+ DeviceObject = irpStack->DeviceObject;
+ }
+ ASSERT(DeviceObject);
+
+ deviceExtension = DeviceObject->DeviceExtension;
+ cddata = (PCDROM_DATA) (deviceExtension + 1);
+ readCapacityBuffer = srb->DataBuffer;
+
+ if ((NT_SUCCESS(Irp->IoStatus.Status)) && (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_SUCCESS)) {
+ PFOUR_BYTE from;
+ PFOUR_BYTE to;
+
+ DebugPrint((2, "CdRomUpdateCapacityCompletion: [%lx] successful completion of buddy-irp %lx\n", originalIrp, Irp));
+ //
+ // Copy sector size from read capacity buffer to device extension
+ // in reverse byte order.
+ //
+
+ from = (PFOUR_BYTE) &readCapacityBuffer->BytesPerBlock;
+ to = (PFOUR_BYTE) &deviceExtension->DiskGeometry->BytesPerSector;
+ to->Byte0 = from->Byte3;
+ to->Byte1 = from->Byte2;
+ to->Byte2 = from->Byte1;
+ to->Byte3 = from->Byte0;
+
+ //
+ // Using the new BytesPerBlock, calculate and store the SectorShift.
+ //
+
+ WHICH_BIT(deviceExtension->DiskGeometry->BytesPerSector, deviceExtension->SectorShift);
+
+ //
+ // Copy last sector in reverse byte order.
+ //
+
+ from = (PFOUR_BYTE) &readCapacityBuffer->LogicalBlockAddress;
+ to = (PFOUR_BYTE) &lastSector;
+ to->Byte0 = from->Byte3;
+ to->Byte1 = from->Byte2;
+ to->Byte2 = from->Byte1;
+ to->Byte3 = from->Byte0;
+ deviceExtension->PartitionLength.QuadPart = (LONGLONG)(lastSector + 1);
+
+ //
+ // Calculate number of cylinders.
+ //
+
+ deviceExtension->DiskGeometry->Cylinders.QuadPart = (LONGLONG)((lastSector + 1)/(32 * 64));
+ deviceExtension->PartitionLength.QuadPart =
+ (deviceExtension->PartitionLength.QuadPart << deviceExtension->SectorShift);
+ deviceExtension->DiskGeometry->MediaType = RemovableMedia;
+
+ //
+ // Assume sectors per track are 32;
+ //
+
+ deviceExtension->DiskGeometry->SectorsPerTrack = 32;
+
+ //
+ // Assume tracks per cylinder (number of heads) is 64.
+ //
+
+ deviceExtension->DiskGeometry->TracksPerCylinder = 64;
+
+ } else {
+
+ DebugPrint((1, "CdRomUpdateCapacityCompletion: [%lx] unsuccessful completion of buddy-irp %lx (status - %lx)\n", originalIrp, Irp, Irp->IoStatus.Status));
+
+ if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
+ ScsiClassReleaseQueue(DeviceObject);
+ }
+
+ retry = ScsiClassInterpretSenseInfo(DeviceObject,
+ srb,
+ IRP_MJ_SCSI,
+ 0,
+ retryCount,
+ &status);
+ if (retry) {
+ retryCount--;
+ if (retryCount) {
+ PCDB cdb;
+
+ DebugPrint((1, "CdRomUpdateCapacityCompletion: [%lx] Retrying request %lx .. thread is %lx\n", originalIrp, Irp, Irp->Tail.Overlay.Thread));
+ //
+ // set up a one shot timer to get this process started over
+ //
+
+ irpStack->Parameters.Others.Argument1 = (PVOID) retryCount;
+ irpStack->Parameters.Others.Argument2 = (PVOID) originalIrp;
+ irpStack->Parameters.Others.Argument3 = (PVOID) 2;
+
+ //
+ // Setup the IRP to be submitted again in the timer routine.
+ //
+
+ irpStack = IoGetNextIrpStackLocation(Irp);
+ irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
+ irpStack->Parameters.Scsi.Srb = srb;
+ IoSetCompletionRoutine(Irp,
+ CdRomUpdateGeometryCompletion,
+ srb,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ //
+ // Set up the SRB for read capacity.
+ //
+
+ srb->CdbLength = 10;
+ srb->TimeOutValue = deviceExtension->TimeOutValue;
+ srb->SrbStatus = srb->ScsiStatus = 0;
+ srb->NextSrb = 0;
+ srb->Length = SCSI_REQUEST_BLOCK_SIZE;
+ srb->PathId = deviceExtension->PathId;
+ srb->TargetId = deviceExtension->TargetId;
+ srb->Lun = deviceExtension->Lun;
+ srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
+ srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
+ srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
+
+ //
+ // Set up the CDB
+ //
+
+ cdb = (PCDB) &srb->Cdb[0];
+ cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
+ cdb->CDB10.LogicalUnitNumber = deviceExtension->Lun;
+
+ //
+ // Requests queued onto this list will be sent to the
+ // lower level driver during CdRomTickHandler
+ //
+
+ ExInterlockedInsertHeadList(&cddata->TimerIrpList,
+ &Irp->Tail.Overlay.ListEntry,
+ &cddata->TimerIrpSpinLock);
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+ } else {
+
+ //
+ // This has been bounced for a number of times. Error the
+ // original request.
+ //
+
+ originalIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ RtlZeroMemory(deviceExtension->DiskGeometry, sizeof(DISK_GEOMETRY));
+ deviceExtension->DiskGeometry->BytesPerSector = 2048;
+ deviceExtension->SectorShift = 11;
+ deviceExtension->PartitionLength.QuadPart = (LONGLONG)(0x7fffffff);
+ deviceExtension->DiskGeometry->MediaType = RemovableMedia;
+ }
+ } else {
+
+ //
+ // Set up reasonable defaults
+ //
+
+ RtlZeroMemory(deviceExtension->DiskGeometry, sizeof(DISK_GEOMETRY));
+ deviceExtension->DiskGeometry->BytesPerSector = 2048;
+ deviceExtension->SectorShift = 11;
+ deviceExtension->PartitionLength.QuadPart = (LONGLONG)(0x7fffffff);
+ deviceExtension->DiskGeometry->MediaType = RemovableMedia;
+ }
+ }
+
+ //
+ // Free resources held.
+ //
+
+ ExFreePool(srb->SenseInfoBuffer);
+ ExFreePool(srb->DataBuffer);
+ ExFreePool(srb);
+ if (Irp->MdlAddress) {
+ IoFreeMdl(Irp->MdlAddress);
+ }
+ IoFreeIrp(Irp);
+ if (originalIrp->Tail.Overlay.Thread) {
+
+ DebugPrint((2, "CdRomUpdateCapacityCompletion: [%lx] completing original IRP\n", originalIrp));
+ IoCompleteRequest(originalIrp, IO_DISK_INCREMENT);
- DPRINT ("CdromTimerRoutine() called\n");
- WorkItem = IoAllocateWorkItem(DeviceObject);
- if (!WorkItem)
- {
- return;
+ } else {
+ DebugPrint((1, "CdRomUpdateCapacityCompletion: [%lx] original irp has "
+ "no thread\n",
+ originalIrp
+ ));
}
- IoQueueWorkItem(WorkItem,
- CdromWorkItem,
- DelayedWorkQueue,
- WorkItem);
+ //
+ // It's now safe to either start the next request or let the waiting ioctl
+ // request continue along it's merry way
+ //
+
+ IoStartNextPacket(DeviceObject, FALSE);
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
}
+\f
+NTSTATUS
+STDCALL
+CdRomUpdateCapacity(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PIRP IrpToComplete,
+ IN OPTIONAL PKEVENT IoctlEvent
+ )
+
+/*++
+
+Routine Description:
+
+ This routine updates the capacity of the disk as recorded in the device extension.
+ It also completes the IRP given with STATUS_VERIFY_REQUIRED. This routine is called
+ when a media change has occurred and it is necessary to determine the capacity of the
+ new media prior to the next access.
+
+Arguments:
+
+ DeviceExtension - the device to update
+ IrpToComplete - the request that needs to be completed when done.
+
+Return Value:
+
+ NTSTATUS
+
+--*/
-VOID STDCALL
-CdromWorkItem(IN PDEVICE_OBJECT DeviceObject,
- IN PVOID Context)
{
- PIRP Irp;
- KEVENT Event;
- IO_STATUS_BLOCK IoStatus;
- NTSTATUS Status;
-
- DPRINT("CdromWorkItem() called\n");
-
- IoFreeWorkItem((PIO_WORKITEM) Context);
-
- KeInitializeEvent(&Event,
- NotificationEvent,
- FALSE);
-
- Irp = IoBuildDeviceIoControlRequest(IOCTL_CDROM_CHECK_VERIFY,
- DeviceObject,
- NULL,
- 0,
- NULL,
- 0,
- FALSE,
- &Event,
- &IoStatus);
- if (Irp == NULL)
- {
- DPRINT("IoBuildDeviceIoControlRequest failed\n");
- return;
- }
-
- Status = IoCallDriver(DeviceObject, Irp);
- DPRINT("Status: %x\n", Status);
-
- if (Status == STATUS_PENDING)
- {
- KeWaitForSingleObject(&Event,
- Suspended,
- KernelMode,
- FALSE,
- NULL);
+ PCDB cdb;
+ PIRP irp;
+ PSCSI_REQUEST_BLOCK srb;
+ PREAD_CAPACITY_DATA capacityBuffer;
+ PIO_STACK_LOCATION irpStack;
+ PUCHAR senseBuffer;
+ NTSTATUS status;
+
+ irp = IoAllocateIrp((CCHAR)(DeviceExtension->DeviceObject->StackSize+1),
+ FALSE);
+
+ if (irp) {
+
+ srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
+ if (srb) {
+ capacityBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
+ sizeof(READ_CAPACITY_DATA));
+
+ if (capacityBuffer) {
+
+
+ senseBuffer = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
+
+ if (senseBuffer) {
+
+ irp->MdlAddress = IoAllocateMdl(capacityBuffer,
+ sizeof(READ_CAPACITY_DATA),
+ FALSE,
+ FALSE,
+ (PIRP) NULL);
+
+ if (irp->MdlAddress) {
+
+ //
+ // Have all resources. Set up the IRP to send for the capacity.
+ //
+
+ IoSetNextIrpStackLocation(irp);
+ irp->IoStatus.Status = STATUS_SUCCESS;
+ irp->IoStatus.Information = 0;
+ irp->Flags = 0;
+ irp->UserBuffer = NULL;
+
+ //
+ // Save the device object and retry count in a private stack location.
+ //
+
+ irpStack = IoGetCurrentIrpStackLocation(irp);
+ irpStack->DeviceObject = DeviceExtension->DeviceObject;
+ irpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
+ irpStack->Parameters.Others.Argument2 = (PVOID) IrpToComplete;
+
+ //
+ // Construct the IRP stack for the lower level driver.
+ //
+
+ irpStack = IoGetNextIrpStackLocation(irp);
+ irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
+ irpStack->Parameters.Scsi.Srb = srb;
+ IoSetCompletionRoutine(irp,
+ CdRomUpdateGeometryCompletion,
+ srb,
+ TRUE,
+ TRUE,
+ TRUE);
+ //
+ // Prepare the MDL
+ //
+
+ MmBuildMdlForNonPagedPool(irp->MdlAddress);
+
+
+ //
+ // Set up the SRB for read capacity.
+ //
+
+ RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
+ RtlZeroMemory(senseBuffer, SENSE_BUFFER_SIZE);
+ srb->CdbLength = 10;
+ srb->TimeOutValue = DeviceExtension->TimeOutValue;
+ srb->SrbStatus = srb->ScsiStatus = 0;
+ srb->NextSrb = 0;
+ srb->Length = SCSI_REQUEST_BLOCK_SIZE;
+ srb->PathId = DeviceExtension->PathId;
+ srb->TargetId = DeviceExtension->TargetId;
+ srb->Lun = DeviceExtension->Lun;
+ srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
+ srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
+ srb->DataBuffer = capacityBuffer;
+ srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
+ srb->OriginalRequest = irp;
+ srb->SenseInfoBuffer = senseBuffer;
+ srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
+
+ //
+ // Set up the CDB
+ //
+
+ cdb = (PCDB) &srb->Cdb[0];
+ cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
+ cdb->CDB10.LogicalUnitNumber = DeviceExtension->Lun;
+
+ //
+ // Set the return value in the IRP that will be completed
+ // upon completion of the read capacity.
+ //
+
+ IrpToComplete->IoStatus.Status = STATUS_VERIFY_REQUIRED;
+ IoMarkIrpPending(IrpToComplete);
+
+ status = IoCallDriver(DeviceExtension->PortDeviceObject, irp);
+
+ //
+ // status is not checked because the completion routine for this
+ // IRP will always get called and it will free the resources.
+ //
+
+ return STATUS_PENDING;
+
+ } else {
+ ExFreePool(senseBuffer);
+ ExFreePool(capacityBuffer);
+ ExFreePool(srb);
+ IoFreeIrp(irp);
+ }
+ } else {
+ ExFreePool(capacityBuffer);
+ ExFreePool(srb);
+ IoFreeIrp(irp);
+ }
+ } else {
+ ExFreePool(srb);
+ IoFreeIrp(irp);
+ }
+ } else {
+ IoFreeIrp(irp);
+ }
}
+
+ return STATUS_INSUFFICIENT_RESOURCES;
}
-/* EOF */
+\f
+NTSTATUS
+STDCALL
+CdRomClassIoctlCompletion(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine signals the event used by CdRomDeviceControl to synchronize
+ class driver (and lower level driver) ioctls with cdrom's startio routine.
+ The irp completion is short-circuited so that CdRomDeviceControl can
+ reissue it once it wakes up.
+
+Arguments:
+
+ DeviceObject - the device object
+ Irp - the request we are synchronizing
+ Context - a PKEVENT that we need to signal
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+
+{
+ PKEVENT syncEvent = (PKEVENT) Context;
+
+ DebugPrint((2, "CdRomClassIoctlCompletion: setting event for irp %#08lx\n",
+ Irp
+ ));
+
+ KeSetEvent(syncEvent, IO_DISK_INCREMENT, FALSE);
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}