ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

cdrom.c
Go to the documentation of this file.
00001 /*--
00002 
00003 Copyright (C) Microsoft Corporation, 1991 - 1999
00004 
00005 Module Name:
00006 
00007     cdrom.c
00008 
00009 Abstract:
00010 
00011     The CDROM class driver tranlates IRPs to SRBs with embedded CDBs
00012     and sends them to its devices through the port driver.
00013 
00014 Environment:
00015 
00016     kernel mode only
00017 
00018 Notes:
00019 
00020     SCSI Tape, CDRom and Disk class drivers share common routines
00021     that can be found in the CLASS directory (..\ntos\dd\class).
00022 
00023 Revision History:
00024 
00025 --*/
00026 
00027 #include "stddef.h"
00028 #include "string.h"
00029 
00030 #include "ntddk.h"
00031 #include "initguid.h"
00032 
00033 #include "ntddcdvd.h"
00034 #include "classpnp.h"
00035 
00036 #include "ntddstor.h"
00037 #include "cdrom.h"
00038 
00039 #ifdef ALLOC_PRAGMA
00040 
00041 #pragma alloc_text(INIT, DriverEntry)
00042 
00043 #pragma alloc_text(PAGE, CdRomUnload)
00044 #pragma alloc_text(PAGE, CdRomAddDevice)
00045 #pragma alloc_text(PAGE, CdRomCreateDeviceObject)
00046 #pragma alloc_text(PAGE, CdRomStartDevice)
00047 #pragma alloc_text(PAGE, ScanForSpecial)
00048 #pragma alloc_text(PAGE, ScanForSpecialHandler)
00049 #pragma alloc_text(PAGE, CdRomRemoveDevice)
00050 #pragma alloc_text(PAGE, CdRomGetDeviceType)
00051 #pragma alloc_text(PAGE, CdRomReadWriteVerification)
00052 #pragma alloc_text(PAGE, CdRomGetDeviceParameter)
00053 #pragma alloc_text(PAGE, CdRomSetDeviceParameter)
00054 #pragma alloc_text(PAGE, CdRomPickDvdRegion)
00055 #pragma alloc_text(PAGE, CdRomIsPlayActive)
00056 
00057 #pragma alloc_text(PAGEHITA, HitachiProcessError)
00058 #pragma alloc_text(PAGEHIT2, HitachiProcessErrorGD2000)
00059 
00060 #pragma alloc_text(PAGETOSH, ToshibaProcessErrorCompletion)
00061 #pragma alloc_text(PAGETOSH, ToshibaProcessError)
00062 
00063 #endif
00064 
00065 #define IS_WRITE_REQUEST(irpStack)                                             \
00066  (irpStack->MajorFunction == IRP_MJ_WRITE)
00067  
00068 #define IS_READ_WRITE_REQUEST(irpStack)                                        \
00069 ((irpStack->MajorFunction == IRP_MJ_READ)  ||                                  \
00070  (irpStack->MajorFunction == IRP_MJ_WRITE) ||                                  \
00071  ((irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) &&                        \
00072   (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_RAW_READ)))
00073 
00074 
00075 
00076 
00077 NTSTATUS
00078 NTAPI
00079 DriverEntry(
00080     IN PDRIVER_OBJECT DriverObject,
00081     IN PUNICODE_STRING RegistryPath
00082     )
00083 
00084 /*++
00085 
00086 Routine Description:
00087 
00088     This routine initializes the cdrom class driver.
00089 
00090 Arguments:
00091 
00092     DriverObject - Pointer to driver object created by system.
00093 
00094     RegistryPath - Pointer to the name of the services node for this driver.
00095 
00096 Return Value:
00097 
00098     The function value is the final status from the initialization operation.
00099 
00100 --*/
00101 
00102 {
00103     CLASS_INIT_DATA InitializationData;
00104     PCDROM_DRIVER_EXTENSION driverExtension;
00105     NTSTATUS status;
00106     
00107     PAGED_CODE();
00108     
00109     WPP_INIT_TRACING(DriverObject, RegistryPath);
00110 
00111     TraceLog((CdromDebugTrace,
00112                 "CDROM.SYS DriverObject %p loading\n", DriverObject));
00113     
00114     status = IoAllocateDriverObjectExtension(DriverObject,
00115                                              CDROM_DRIVER_EXTENSION_ID,
00116                                              sizeof(CDROM_DRIVER_EXTENSION),
00117                                              (PVOID*)&driverExtension);    
00118 
00119     if (!NT_SUCCESS(status)) {
00120         TraceLog((CdromDebugWarning,
00121                     "DriverEntry !! no DriverObjectExtension %x\n", status));
00122         return status;
00123     }
00124 
00125     //
00126     // always zero the memory, since we are now reloading the driver.
00127     //
00128 
00129     RtlZeroMemory(driverExtension, sizeof(CDROM_DRIVER_EXTENSION));
00130 
00131     //
00132     // Zero InitData
00133     //
00134 
00135     RtlZeroMemory (&InitializationData, sizeof(CLASS_INIT_DATA));
00136 
00137     //
00138     // Set sizes
00139     //
00140 
00141     InitializationData.InitializationDataSize = sizeof(CLASS_INIT_DATA);
00142 
00143     InitializationData.FdoData.DeviceExtensionSize = DEVICE_EXTENSION_SIZE;
00144 
00145     InitializationData.FdoData.DeviceType = FILE_DEVICE_CD_ROM;
00146     InitializationData.FdoData.DeviceCharacteristics =
00147         FILE_REMOVABLE_MEDIA | FILE_DEVICE_SECURE_OPEN;
00148 
00149     //
00150     // Set entry points
00151     //
00152 
00153     InitializationData.FdoData.ClassError = CdRomErrorHandler;
00154     InitializationData.FdoData.ClassInitDevice = CdRomInitDevice;
00155     InitializationData.FdoData.ClassStartDevice = CdRomStartDevice;
00156     InitializationData.FdoData.ClassStopDevice = CdRomStopDevice;
00157     InitializationData.FdoData.ClassRemoveDevice = CdRomRemoveDevice;
00158 
00159     InitializationData.FdoData.ClassReadWriteVerification = CdRomReadWriteVerification;
00160     InitializationData.FdoData.ClassDeviceControl = CdRomDeviceControlDispatch;
00161 
00162     InitializationData.FdoData.ClassPowerDevice = ClassSpinDownPowerHandler;
00163     InitializationData.FdoData.ClassShutdownFlush = CdRomShutdownFlush;
00164     InitializationData.FdoData.ClassCreateClose = NULL;
00165 
00166     InitializationData.ClassStartIo = CdRomStartIo;
00167     InitializationData.ClassAddDevice = CdRomAddDevice;
00168 
00169     InitializationData.ClassTick = CdRomTickHandler;
00170     InitializationData.ClassUnload = CdRomUnload;
00171 
00172     //
00173     // Call the class init routine
00174     //
00175     return ClassInitialize( DriverObject, RegistryPath, &InitializationData);
00176 
00177 } // end DriverEntry()
00178 
00179 
00180 VOID
00181 CdRomUnload(
00182     IN PDRIVER_OBJECT DriverObject
00183     )
00184 {
00185     PAGED_CODE();
00186     UNREFERENCED_PARAMETER(DriverObject);
00187     TraceLog((CdromDebugTrace,
00188                 "CDROM.SYS DriverObject %p unloading\n", DriverObject));
00189     WPP_CLEANUP(DriverObject);
00190     return;
00191 } // end CdRomUnload()
00192 
00193 
00194 NTSTATUS
00195 CdRomAddDevice(
00196     IN PDRIVER_OBJECT DriverObject,
00197     IN PDEVICE_OBJECT PhysicalDeviceObject
00198     )
00199 
00200 /*++
00201 
00202 Routine Description:
00203 
00204     This routine creates and initializes a new FDO for the corresponding
00205     PDO.  It may perform property queries on the FDO but cannot do any
00206     media access operations.
00207 
00208 Arguments:
00209 
00210     DriverObject - CDROM class driver object.
00211 
00212     Pdo - the physical device object we are being added to
00213 
00214 Return Value:
00215 
00216     status
00217 
00218 --*/
00219 
00220 {
00221     NTSTATUS status;
00222 
00223     PAGED_CODE();
00224 
00225     //
00226     // Get the address of the count of the number of cdroms already initialized.
00227     //
00228     DbgPrint("add device\n");
00229 
00230     status = CdRomCreateDeviceObject(DriverObject,
00231                                      PhysicalDeviceObject);
00232 
00233     //
00234     // Note: this always increments driver extension counter
00235     //       it will eventually wrap, and fail additions
00236     //       if an existing cdrom has the given number.
00237     //       so unlikely that we won't even bother considering
00238     //       this case, since the cure is quite likely worse
00239     //       than the symptoms.
00240     //
00241 
00242     if(NT_SUCCESS(status)) {
00243 
00244         //
00245         // keep track of the total number of active cdroms in IoGet(),
00246         // as some programs use this to determine when they have found
00247         // all the cdroms in the system.
00248         //
00249 
00250         TraceLog((CdromDebugTrace, "CDROM.SYS Add succeeded\n"));
00251         IoGetConfigurationInformation()->CdRomCount++;
00252 
00253     } else {
00254 
00255         TraceLog((CdromDebugWarning,
00256                     "CDROM.SYS Add failed! %x\n", status));
00257 
00258     }
00259 
00260     return status;
00261 }
00262 
00263 
00264 NTSTATUS
00265 CdRomCreateDeviceObject(
00266     IN PDRIVER_OBJECT DriverObject,
00267     IN PDEVICE_OBJECT PhysicalDeviceObject
00268     )
00269 
00270 /*++
00271 
00272 Routine Description:
00273 
00274     This routine creates an object for the device and then calls the
00275     SCSI port driver for media capacity and sector size.
00276 
00277 Arguments:
00278 
00279     DriverObject - Pointer to driver object created by system.
00280     PortDeviceObject - to connect to SCSI port driver.
00281     DeviceCount - Number of previously installed CDROMs.
00282     PortCapabilities - Pointer to structure returned by SCSI port
00283         driver describing adapter capabilites (and limitations).
00284     LunInfo - Pointer to configuration information for this device.
00285 
00286 Return Value:
00287 
00288     NTSTATUS
00289 
00290 --*/
00291 {
00292     UCHAR ntNameBuffer[64];
00293     STRING ntNameString;
00294     NTSTATUS status;
00295 
00296     PDEVICE_OBJECT lowerDevice = NULL;
00297     PDEVICE_OBJECT deviceObject = NULL;
00298     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = NULL;
00299     PCDROM_DATA cdData = NULL;
00300     PCDROM_DRIVER_EXTENSION driverExtension = NULL;
00301     ULONG deviceNumber;
00302 
00303     CCHAR                   dosNameBuffer[64];
00304     CCHAR                   deviceNameBuffer[64];
00305     STRING                  deviceNameString;
00306     STRING                  dosString;
00307     UNICODE_STRING          dosUnicodeString;
00308     UNICODE_STRING          unicodeString;
00309 
00310     PAGED_CODE();
00311 
00312     //
00313     // Claim the device. Note that any errors after this
00314     // will goto the generic handler, where the device will
00315     // be released.
00316     //
00317 
00318     lowerDevice = IoGetAttachedDeviceReference(PhysicalDeviceObject);
00319 
00320     status = ClassClaimDevice(lowerDevice, FALSE);
00321 
00322     if(!NT_SUCCESS(status)) {
00323 
00324         //
00325         // Someone already had this device - we're in trouble
00326         //
00327 
00328         ObDereferenceObject(lowerDevice);
00329         return status;
00330     }
00331 
00332     //
00333     // Create device object for this device by first getting a unique name
00334     // for the device and then creating it.
00335     //
00336 
00337     driverExtension = IoGetDriverObjectExtension(DriverObject,
00338                                                  CDROM_DRIVER_EXTENSION_ID);
00339     ASSERT(driverExtension != NULL);
00340 
00341     //
00342     // InterlockedCdRomCounter is biased by 1.
00343     //
00344 
00345     deviceNumber = InterlockedIncrement(&driverExtension->InterlockedCdRomCounter) - 1;
00346     sprintf(ntNameBuffer, "\\Device\\CdRom%d", deviceNumber);
00347 
00348 
00349     status = ClassCreateDeviceObject(DriverObject,
00350                                      ntNameBuffer,
00351                                      PhysicalDeviceObject,
00352                                      TRUE,
00353                                      &deviceObject);
00354 
00355     if (!NT_SUCCESS(status)) {
00356         TraceLog((CdromDebugWarning,
00357                     "CreateCdRomDeviceObjects: Can not create device %s\n",
00358                     ntNameBuffer));
00359 
00360         goto CreateCdRomDeviceObjectExit;
00361     }
00362 
00363     //
00364     // Indicate that IRPs should include MDLs.
00365     //
00366 
00367     SET_FLAG(deviceObject->Flags, DO_DIRECT_IO);
00368 
00369     fdoExtension = deviceObject->DeviceExtension;
00370 
00371     //
00372     // Back pointer to device object.
00373     //
00374 
00375     fdoExtension->CommonExtension.DeviceObject = deviceObject;
00376 
00377     //
00378     // This is the physical device.
00379     //
00380 
00381     fdoExtension->CommonExtension.PartitionZeroExtension = fdoExtension;
00382 
00383     //
00384     // Initialize lock count to zero. The lock count is used to
00385     // disable the ejection mechanism when media is mounted.
00386     //
00387 
00388     fdoExtension->LockCount = 0;
00389 
00390     //
00391     // Save system cdrom number
00392     //
00393 
00394     fdoExtension->DeviceNumber = deviceNumber;
00395 
00396     //
00397     // Set the alignment requirements for the device based on the
00398     // host adapter requirements
00399     //
00400 
00401     if (lowerDevice->AlignmentRequirement > deviceObject->AlignmentRequirement) {
00402         deviceObject->AlignmentRequirement = lowerDevice->AlignmentRequirement;
00403     }
00404 
00405     //
00406     // Save the device descriptors
00407     //
00408 
00409     fdoExtension->AdapterDescriptor = NULL;
00410 
00411     fdoExtension->DeviceDescriptor = NULL;
00412 
00413     //
00414     // Clear the SrbFlags and disable synchronous transfers
00415     //
00416 
00417     fdoExtension->SrbFlags = SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
00418 
00419     //
00420     // Finally, attach to the PDO
00421     //
00422 
00423     fdoExtension->LowerPdo = PhysicalDeviceObject;
00424 
00425     fdoExtension->CommonExtension.LowerDeviceObject =
00426         IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject);
00427 
00428     if(fdoExtension->CommonExtension.LowerDeviceObject == NULL) {
00429 
00430         //
00431         // Uh - oh, we couldn't attach
00432         // cleanup and return
00433         //
00434 
00435         status = STATUS_UNSUCCESSFUL;
00436         goto CreateCdRomDeviceObjectExit;
00437     }
00438 
00439     //
00440     // CdRom uses an extra stack location for synchronizing it's start io
00441     // routine
00442     //
00443 
00444     deviceObject->StackSize++;
00445 
00446     //
00447     // cdData is used a few times below
00448     //
00449 
00450     cdData = fdoExtension->CommonExtension.DriverData;
00451 
00452     //
00453     // For NTMS to be able to easily determine drives-drv. letter matches.
00454     //
00455 
00456     status = CdRomCreateWellKnownName( deviceObject );
00457 
00458     if (!NT_SUCCESS(status)) {
00459         TraceLog((CdromDebugWarning,
00460                     "CdromCreateDeviceObjects: unable to create symbolic "
00461                     "link for device %wZ\n", &fdoExtension->CommonExtension.DeviceName));
00462         TraceLog((CdromDebugWarning,
00463                     "CdromCreateDeviceObjects: (non-fatal error)\n"));
00464     }
00465 
00466     ClassUpdateInformationInRegistry(deviceObject, "CdRom",
00467                                      fdoExtension->DeviceNumber, NULL, 0);
00468 
00469     //
00470     // from above IoGetAttachedDeviceReference
00471     //
00472 
00473     ObDereferenceObject(lowerDevice);
00474 
00475     //
00476     // need to init timerlist here in case a remove occurs
00477     // without a start, since we check the list is empty on remove.
00478     //
00479 
00480     cdData->DelayedRetryIrp = NULL;
00481     cdData->DelayedRetryInterval = 0;
00482 
00483     //
00484     // need this to be initialized for RPC Phase 1 drives (rpc0)
00485     //
00486 
00487     KeInitializeMutex(&cdData->Rpc0RegionMutex, 0);
00488     
00489     //
00490     // The device is initialized properly - mark it as such.
00491     //
00492 
00493     CLEAR_FLAG(deviceObject->Flags, DO_DEVICE_INITIALIZING);
00494 
00495     return(STATUS_SUCCESS);
00496 
00497 CreateCdRomDeviceObjectExit:
00498 
00499     //
00500     // Release the device since an error occured.
00501     //
00502 
00503     // ClassClaimDevice(PortDeviceObject,
00504     //                      LunInfo,
00505     //                      TRUE,
00506     //                      NULL);
00507 
00508     //
00509     // from above IoGetAttachedDeviceReference
00510     //
00511 
00512     ObDereferenceObject(lowerDevice);
00513 
00514     if (deviceObject != NULL) {
00515         IoDeleteDevice(deviceObject);
00516     }
00517 
00518     return status;
00519 
00520 } // end CreateCdRomDeviceObject()
00521 
00522 
00523 NTSTATUS
00524 CdRomInitDevice(
00525     IN PDEVICE_OBJECT Fdo
00526     )
00527 
00528 /*++
00529 
00530 Routine Description:
00531 
00532     This routine will complete the cd-rom initialization.  This includes
00533     allocating sense info buffers and srb s-lists, reading drive capacity
00534     and setting up Media Change Notification (autorun).
00535 
00536     This routine will not clean up allocate resources if it fails - that
00537     is left for device stop/removal
00538 
00539 Arguments:
00540 
00541     Fdo - a pointer to the functional device object for this device
00542 
00543 Return Value:
00544 
00545     status
00546 
00547 --*/
00548 
00549 {
00550     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
00551     PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
00552     PCLASS_DRIVER_EXTENSION driverExtension = ClassGetDriverExtension(
00553                                                 Fdo->DriverObject);
00554 
00555     PVOID senseData = NULL;
00556 
00557     ULONG timeOut;
00558     PCDROM_DATA cddata = NULL;
00559 
00560     BOOLEAN changerDevice;
00561     BOOLEAN isMmcDevice = FALSE;
00562 
00563     ULONG bps;
00564     ULONG lastBit;
00565 
00566 
00567     NTSTATUS status;
00568 
00569     PAGED_CODE();
00570 
00571     //
00572     // Build the lookaside list for srb's for the physical disk.  Should only
00573     // need a couple.
00574     //
00575 
00576     ClassInitializeSrbLookasideList(&(fdoExtension->CommonExtension),
00577                                     CDROM_SRB_LIST_SIZE);
00578 
00579     //
00580     // Allocate request sense buffer.
00581     //
00582 
00583     senseData = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
00584                                       SENSE_BUFFER_SIZE,
00585                                       CDROM_TAG_SENSE_INFO);
00586 
00587     if (senseData == NULL) {
00588 
00589         //
00590         // The buffer cannot be allocated.
00591         //
00592 
00593         status = STATUS_INSUFFICIENT_RESOURCES;
00594         goto CdRomInitDeviceExit;
00595     }
00596 
00597     //
00598     // Set the sense data pointer in the device extension.
00599     //
00600 
00601     fdoExtension->SenseData = senseData;
00602 
00603     //
00604     // CDROMs are not partitionable so starting offset is 0.
00605     //
00606 
00607     commonExtension->StartingOffset.LowPart = 0;
00608     commonExtension->StartingOffset.HighPart = 0;
00609 
00610     //
00611     // Set timeout value in seconds.
00612     //
00613 
00614     timeOut = ClassQueryTimeOutRegistryValue(Fdo);
00615     if (timeOut) {
00616         fdoExtension->TimeOutValue = timeOut;
00617     } else {
00618         fdoExtension->TimeOutValue = SCSI_CDROM_TIMEOUT;
00619     }
00620 
00621     cddata = (PCDROM_DATA)(commonExtension->DriverData);
00622 
00623     //
00624     // Set up media change support defaults.
00625     //
00626 
00627     KeInitializeSpinLock(&cddata->DelayedRetrySpinLock);
00628 
00629     cddata->DelayedRetryIrp = NULL;
00630     cddata->DelayedRetryInterval = 0;
00631     cddata->Mmc.WriteAllowed = FALSE;
00632 
00633     //
00634     // Scan for  controllers that require special processing.
00635     //
00636 
00637     ScanForSpecial(Fdo);
00638 
00639     //
00640     // Determine if the drive is MMC-Capable
00641     //
00642 
00643     CdRomIsDeviceMmcDevice(Fdo, &isMmcDevice);
00644 
00645     if (!isMmcDevice) {
00646 
00647         SET_FLAG(Fdo->Characteristics, FILE_READ_ONLY_DEVICE);
00648     
00649     } else {
00650         
00651         //
00652         // the drive supports at least a subset of MMC commands
00653         // (and therefore supports READ_CD, etc...)
00654         //
00655 
00656         cddata->Mmc.IsMmc = TRUE;
00657         
00658         //
00659         // allocate a buffer for all the capabilities and such
00660         //
00661 
00662         status = CdRomAllocateMmcResources(Fdo);
00663         if (!NT_SUCCESS(status)) {
00664             goto CdRomInitDeviceExit;
00665         }
00666         
00667 
00668 #if 0
00669         //
00670         // determine all the various media types from the profiles feature
00671         //
00672         {
00673             PFEATURE_DATA_PROFILE_LIST profileHeader;
00674             ULONG mediaTypes = 0;
00675             ULONG i;
00676 
00677             KdPrintEx((DPFLTR_CDROM_ID, CdromDebugError,
00678                        "Checking all profiles for media types supported.\n"
00679                        ));
00680 
00681             profileHeader = CdRomFindFeaturePage(cddata->Mmc.CapabilitiesBuffer,
00682                                                  cddata->Mmc.CapabilitiesBufferSize,
00683                                                  FeatureProfileList);
00684             if (profileHeader == NULL) {
00685 
00686                 //
00687                 // if profiles don't exist, there is something seriously
00688                 // wrong with this command -- it's either not a cdrom or
00689                 // one that hasn't implemented the spec correctly.  exit
00690                 // now while we have the chance to do so safely.
00691                 //
00692                 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugError,
00693                            "CdromDevice supports GET_CONFIGURATION, but "
00694                            "doesn't provide profiles for PDO %p!\n",
00695                            fdoExtension->LowerPdo));
00696                 status = STATUS_DEVICE_CONFIGURATION_ERROR;
00697                 goto CdRomInitDeviceExit;
00698 
00699             }
00700 
00701             for (i = 0; i < MAX_CDROM_MEDIA_TYPES; i++) {
00702                 
00703                 BOOLEAN profileFound;
00704                 CdRomFindProfileInProfiles(profileHeader,
00705                                            MediaProfileMatch[i].Profile,
00706                                            &profileFound);
00707                 if (profileFound) {
00708                     
00709                     KdPrintEx((DPFLTR_CDROM_ID, CdromDebugError,
00710                                "CdromInit -> Found Profile %x => Media %x "
00711                                "(%x total)\n",
00712                                MediaProfileMatch[i].Profile,
00713                                MediaProfileMatch[i].Media,
00714                                mediaTypes + 1
00715                                ));
00716                     
00717                     cddata->Mmc.MediaProfileMatches[mediaTypes] =
00718                         MediaProfileMatch[i];
00719                     mediaTypes++;
00720                 
00721                 }
00722 
00723             }
00724 
00725             if (mediaTypes == 0) {
00726 
00727                 //
00728                 // if profiles don't exist, there is something seriously
00729                 // wrong with this command -- it's either not a cdrom or
00730                 // one that hasn't implemented the spec correctly.  exit
00731                 // now while we have the chance to do so safely.
00732                 //
00733                 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugError,
00734                            "CdromDevice supports GET_CONFIGURATION, but "
00735                            "doesn't support any of the standard profiles "
00736                            "for PDO %p!\n", fdoExtension->LowerPdo));
00737                 status = STATUS_DEVICE_CONFIGURATION_ERROR;
00738                 goto CdRomInitDeviceExit;
00739             
00740             }
00741 
00742             cddata->Mmc.MediaTypes = mediaTypes;
00743 
00744 
00745         }
00746 #endif // media checks, and all failure paths due to bad firmware.
00747 
00748         //
00749         // if the drive supports target defect management and sector-addressable
00750         // writes, then we should allow writes to the media.
00751         //
00752 
00753         if (CdRomFindFeaturePage(cddata->Mmc.CapabilitiesBuffer,
00754                                  cddata->Mmc.CapabilitiesBufferSize,
00755                                  FeatureDefectManagement) &&
00756             CdRomFindFeaturePage(cddata->Mmc.CapabilitiesBuffer,
00757                                  cddata->Mmc.CapabilitiesBufferSize,
00758                                  FeatureRandomWritable)) {
00759 
00760             //
00761             // the drive is target defect managed, and supports random writes
00762             // on sector-aligment.  allow writes to occur by setting the error
00763             // handler to point to a private media change detection handler.
00764             //
00765 
00766             KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
00767                        "Found a WRITE capable device: %p\n", Fdo));
00768             
00769             //
00770             // the write specific pages have been found -- 
00771             // set the error handler and set it to require an update!
00772             //
00773 
00774             cddata->Mmc.UpdateState = CdromMmcUpdateRequired;
00775             cddata->ErrorHandler = CdRomMmcErrorHandler;
00776 
00777         }
00778 
00779         //
00780         // ISSUE-2000/4/4-henrygab - mmc-compliant compliant drives should
00781         //                           be initialized based upon reported
00782         //                           capabilities, such as CSS, Analogue Audio,
00783         //                           READ_CD capabilities, and (possibly) even
00784         //                           drive capacity information.
00785         //
00786         
00787         TraceLog((CdromDebugWarning,
00788                   "Defaulting to READ_CD because device %p is MMC compliant\n",
00789                   Fdo));
00790         SET_FLAG(fdoExtension->DeviceFlags, DEV_SAFE_START_UNIT);
00791         SET_FLAG(cddata->XAFlags, XA_USE_READ_CD);
00792 
00793     }
00794 
00795 
00796     //
00797     // Set the default geometry for the cdrom to match what NT 4 used.
00798     // Classpnp will use these values to compute the cylinder count rather
00799     // than using it's NT 5.0 defaults.
00800     //
00801 
00802     fdoExtension->DiskGeometry.TracksPerCylinder = 0x40;
00803     fdoExtension->DiskGeometry.SectorsPerTrack = 0x20;
00804 
00805     //
00806     // Do READ CAPACITY. This SCSI command returns the last sector address
00807     // on the device and the bytes per sector. These are used to calculate
00808     // the drive capacity in bytes.
00809     //
00810     // NOTE: This should be change to send the Srb synchronously, then
00811     // call CdRomInterpretReadCapacity() to properly setup the defaults.
00812     //
00813 
00814     status = ClassReadDriveCapacity(Fdo);
00815 
00816     bps = fdoExtension->DiskGeometry.BytesPerSector;
00817 
00818     if (!NT_SUCCESS(status) || !bps) {
00819 
00820         TraceLog((CdromDebugWarning,
00821                     "CdRomStartDevice: Can't read capacity for device %wZ\n",
00822                     &(fdoExtension->CommonExtension.DeviceName)));
00823 
00824         //
00825         // Set disk geometry to default values (per ISO 9660).
00826         //
00827 
00828         bps = 2048;
00829         fdoExtension->SectorShift = 11;
00830         commonExtension->PartitionLength.QuadPart = (LONGLONG)(0x7fffffff);
00831 
00832     } else {
00833 
00834         //
00835         // Insure that bytes per sector is a power of 2
00836         // This corrects a problem with the HP 4020i CDR where it
00837         // returns an incorrect number for bytes per sector.
00838         //
00839 
00840         lastBit = (ULONG) -1;
00841         while (bps) {
00842             lastBit++;
00843             bps = bps >> 1;
00844         }
00845 
00846         bps = 1 << lastBit;
00847     }
00848     fdoExtension->DiskGeometry.BytesPerSector = bps;
00849     TraceLog((CdromDebugTrace, "CdRomInitDevice: Calc'd bps = %x\n", bps));
00850 
00851 
00852     ClassInitializeMediaChangeDetection(fdoExtension, "CdRom");
00853 
00854 
00855     //
00856     // test for audio read capabilities
00857     //
00858 
00859     TraceLog((CdromDebugWarning,
00860               "Detecting XA_READ capabilities\n"));
00861 
00862     if (CdRomGetDeviceType(Fdo) == FILE_DEVICE_DVD) {
00863 
00864         TraceLog((CdromDebugWarning,
00865                     "CdRomInitDevice: DVD Devices require START_UNIT\n"));
00866 
00867 
00868         //
00869         // all DVD devices must support the READ_CD command
00870         //
00871 
00872         TraceLog((CdromDebugWarning,
00873                     "CdRomDetermineRawReadCapabilities: DVD devices "
00874                     "support READ_CD command for FDO %p\n", Fdo));
00875         SET_FLAG(fdoExtension->DeviceFlags, DEV_SAFE_START_UNIT);
00876         SET_FLAG(cddata->XAFlags, XA_USE_READ_CD);
00877 
00878 
00879         status = STATUS_SUCCESS;
00880 
00881     } else if ((fdoExtension->DeviceDescriptor->BusType != BusTypeScsi)  &&
00882                (fdoExtension->DeviceDescriptor->BusType != BusTypeAta)   &&
00883                (fdoExtension->DeviceDescriptor->BusType != BusTypeAtapi) &&
00884                (fdoExtension->DeviceDescriptor->BusType != BusTypeUnknown)
00885                ) {
00886 
00887         //
00888         // devices on the newer busses must support READ_CD command
00889         //
00890 
00891         TraceLog((CdromDebugWarning,
00892                   "CdRomDetermineRawReadCapabilities: Devices for newer "
00893                   "busses must support READ_CD command for FDO %p, Bus %x\n",
00894                   Fdo, fdoExtension->DeviceDescriptor->BusType));
00895         SET_FLAG(fdoExtension->DeviceFlags, DEV_SAFE_START_UNIT);
00896         SET_FLAG(cddata->XAFlags, XA_USE_READ_CD);
00897 
00898     }
00899 
00900     //
00901     // now clear all our READ_CD flags if the drive should have supported
00902     // it, but we are not sure it actually does.  we still won't query
00903     // the drive more than one time if it supports the command.
00904     //
00905 
00906     if (TEST_FLAG(cddata->HackFlags, CDROM_HACK_FORCE_READ_CD_DETECTION)) {
00907 
00908         TraceLog((CdromDebugWarning,
00909                   "Forcing detection of READ_CD for FDO %p because "
00910                   "testing showed some firmware did not properly support it\n",
00911                   Fdo));
00912         CLEAR_FLAG(cddata->XAFlags, XA_USE_READ_CD);
00913 
00914     }
00915 
00916 
00917     //
00918     // read our READ_CD support in the registry if it was seeded.
00919     //
00920     {
00921         ULONG readCdSupported = 0;
00922         
00923         ClassGetDeviceParameter(fdoExtension,
00924                                 CDROM_SUBKEY_NAME,
00925                                 CDROM_READ_CD_NAME,
00926                                 &readCdSupported
00927                                 );
00928         
00929         if (readCdSupported != 0) {
00930             
00931             TraceLog((CdromDebugWarning,
00932                       "Defaulting to READ_CD because previously detected "
00933                       "that the device supports it for Fdo %p.\n",
00934                       Fdo
00935                       ));
00936             SET_FLAG(cddata->XAFlags, XA_USE_READ_CD);
00937 
00938         }
00939 
00940     }
00941 
00942 
00943     //
00944     // backwards-compatible hackish attempt to determine if the drive
00945     // supports any method of reading digital audio from the disc.
00946     //
00947 
00948     if (!TEST_FLAG(cddata->XAFlags, XA_USE_READ_CD)) {
00949 
00950         SCSI_REQUEST_BLOCK srb;
00951         PCDB cdb;
00952         ULONG length;
00953         PUCHAR buffer = NULL;
00954         ULONG count;
00955 
00956         //
00957         // ISSUE-2000/07/05-henrygab - use the mode page to determine
00958         //          READ_CD support, then fall back on the below
00959         //          (unreliable?) hack.
00960         //
00961 
00962         //
00963         // Build the MODE SENSE CDB. The data returned will be kept in the
00964         // device extension and used to set block size.
00965         //
00966 
00967         length = max(sizeof(ERROR_RECOVERY_DATA),sizeof(ERROR_RECOVERY_DATA10));
00968 
00969         buffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
00970                                        length,
00971                                        CDROM_TAG_MODE_DATA);
00972 
00973         if (!buffer) {
00974             TraceLog((CdromDebugWarning,
00975                         "CdRomDetermineRawReadCapabilities: cannot allocate "
00976                         "buffer, so leaving for FDO %p\n", Fdo));
00977             status = STATUS_INSUFFICIENT_RESOURCES;
00978             goto CdRomInitDeviceExit;
00979         }
00980 
00981         for (count = 0; count < 2; count++) {
00982 
00983             if (count == 0) {
00984                 length = sizeof(ERROR_RECOVERY_DATA);
00985             } else {
00986                 length = sizeof(ERROR_RECOVERY_DATA10);
00987             }
00988 
00989             RtlZeroMemory(buffer, length);
00990             RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
00991             cdb = (PCDB)srb.Cdb;
00992 
00993             srb.TimeOutValue = fdoExtension->TimeOutValue;
00994 
00995             if (count == 0) {
00996                 srb.CdbLength = 6;
00997                 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
00998                 cdb->MODE_SENSE.PageCode = 0x1;
00999                 // note: not setting DBD in order to get the block descriptor!
01000                 cdb->MODE_SENSE.AllocationLength = (UCHAR)length;
01001             } else {
01002                 srb.CdbLength = 10;
01003                 cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
01004                 cdb->MODE_SENSE10.PageCode = 0x1;
01005                 // note: not setting DBD in order to get the block descriptor!
01006                 cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(length >> 8);
01007                 cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(length & 0xFF);
01008             }
01009 
01010             status = ClassSendSrbSynchronous(Fdo,
01011                                              &srb,
01012                                              buffer,
01013                                              length,
01014                                              FALSE);
01015 
01016 
01017             if (NT_SUCCESS(status) || (status == STATUS_DATA_OVERRUN)) {
01018 
01019                 //
01020                 // STATUS_DATA_OVERRUN means it's a newer drive with more info
01021                 // to tell us, so it's probably able to support READ_CD
01022                 //
01023 
01024                 RtlZeroMemory(cdb, CDB12GENERIC_LENGTH);
01025 
01026                 srb.CdbLength = 12;
01027                 cdb->READ_CD.OperationCode = SCSIOP_READ_CD;
01028 
01029                 status = ClassSendSrbSynchronous(Fdo,
01030                                                  &srb,
01031                                                  NULL,
01032                                                  0,
01033                                                  FALSE);
01034 
01035                 if (NT_SUCCESS(status) ||
01036                     (status == STATUS_NO_MEDIA_IN_DEVICE) ||
01037                     (status == STATUS_NONEXISTENT_SECTOR) ||
01038                     (status == STATUS_UNRECOGNIZED_MEDIA)
01039                     ) {
01040 
01041                     //
01042                     // READ_CD works
01043                     //
01044 
01045                     TraceLog((CdromDebugWarning,
01046                               "CdRomDetermineRawReadCapabilities: Using "
01047                               "READ_CD for FDO %p due to status %x\n",
01048                               Fdo,
01049                               status));
01050                     SET_FLAG(cddata->XAFlags, XA_USE_READ_CD);
01051                     
01052                     //
01053                     // ignore errors in saving this info
01054                     //
01055                     
01056                     ClassSetDeviceParameter(fdoExtension,
01057                                             CDROM_SUBKEY_NAME,
01058                                             CDROM_READ_CD_NAME,
01059                                             1
01060                                             );
01061                                             
01062 
01063                     break; // out of the for loop
01064 
01065                 }
01066 
01067                 TraceLog((CdromDebugWarning,
01068                             "CdRomDetermineRawReadCapabilities: Using "
01069                             "%s-byte mode switching for FDO %p due to status "
01070                             "%x returned for READ_CD\n",
01071                             ((count == 0) ? "6" : "10"), Fdo, status));
01072 
01073                 if (count == 0) {
01074                     SET_FLAG(cddata->XAFlags, XA_USE_6_BYTE);
01075                     RtlCopyMemory(&cddata->Header,
01076                                   buffer,
01077                                   sizeof(ERROR_RECOVERY_DATA));
01078                     cddata->Header.ModeDataLength = 0;
01079                 } else {
01080                     SET_FLAG(cddata->XAFlags, XA_USE_10_BYTE);
01081                     RtlCopyMemory(&cddata->Header10,
01082                                   buffer,
01083                                   sizeof(ERROR_RECOVERY_DATA10));
01084                     cddata->Header10.ModeDataLength[0] = 0;
01085                     cddata->Header10.ModeDataLength[1] = 0;
01086                 }
01087                 break;  // out of for loop
01088 
01089             }
01090             TraceLog((CdromDebugWarning,
01091                       "FDO %p failed %x byte mode sense, status %x\n",
01092                       Fdo,
01093                       ((count == 0) ? 6 : 10),
01094                       status
01095                       ));
01096 
01097             //
01098             // mode sense failed
01099             //
01100 
01101         } // end of for loop to try 6 and 10-byte mode sense
01102 
01103         if (count == 2) {
01104 
01105             //
01106             // nothing worked.  we probably cannot support digital
01107             // audio extraction from this drive
01108             //
01109 
01110             TraceLog((CdromDebugWarning,
01111                         "CdRomDetermineRawReadCapabilities: FDO %p "
01112                         "cannot support READ_CD\n", Fdo));
01113             CLEAR_FLAG(cddata->XAFlags, XA_PLEXTOR_CDDA);
01114             CLEAR_FLAG(cddata->XAFlags, XA_NEC_CDDA);
01115             SET_FLAG(cddata->XAFlags, XA_NOT_SUPPORTED);
01116 
01117         } // end of count == 2
01118 
01119         //
01120         // free our resources
01121         //
01122 
01123         ExFreePool(buffer);
01124 
01125         //
01126         // set a successful status
01127         // (in case someone later checks this)
01128         //
01129 
01130         status = STATUS_SUCCESS;
01131 
01132     }
01133 
01134     //
01135     // Register interfaces for this device.
01136     //
01137 
01138     {
01139         UNICODE_STRING interfaceName;
01140 
01141         RtlInitUnicodeString(&interfaceName, NULL);
01142 
01143         status = IoRegisterDeviceInterface(fdoExtension->LowerPdo,
01144                                            (LPGUID) &CdRomClassGuid,
01145                                            NULL,
01146                                            &interfaceName);
01147 
01148         if(NT_SUCCESS(status)) {
01149 
01150             cddata->CdromInterfaceString = interfaceName;
01151 
01152             status = IoSetDeviceInterfaceState(
01153                         &interfaceName,
01154                         TRUE);
01155 
01156             if(!NT_SUCCESS(status)) {
01157 
01158                 TraceLog((CdromDebugWarning,
01159                             "CdromInitDevice: Unable to register cdrom "
01160                             "DCA for fdo %p [%lx]\n",
01161                             Fdo, status));
01162             }
01163         }
01164     }
01165 
01166     return(STATUS_SUCCESS);
01167 
01168 CdRomInitDeviceExit:
01169 
01170     CdRomDeAllocateMmcResources(Fdo);    
01171     RtlZeroMemory(&(cddata->Mmc), sizeof(CDROM_MMC_EXTENSION));
01172     
01173     return status;
01174 
01175 }
01176 
01177 
01178 NTSTATUS
01179 CdRomStartDevice(
01180     IN PDEVICE_OBJECT Fdo
01181     )
01182 /*++
01183 
01184 Routine Description:
01185 
01186     This routine starts the timer for the cdrom
01187 
01188 Arguments:
01189 
01190     Fdo - a pointer to the functional device object for this device
01191 
01192 Return Value:
01193 
01194     status
01195 
01196 --*/
01197 
01198 {
01199     PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
01200     PCDROM_DATA cddata = (PCDROM_DATA)(commonExtension->DriverData);
01201     PDVD_COPY_PROTECT_KEY copyProtectKey;
01202     PDVD_RPC_KEY rpcKey;
01203     IO_STATUS_BLOCK ioStatus;
01204     ULONG bufferLen;
01205 
01206     // CdRomCreateWellKnownName(Fdo);
01207 
01208     //
01209     // if we have a DVD-ROM
01210     //    if we have a rpc0 device
01211     //        fake a rpc2 device
01212     //    if device does not have a dvd region set
01213     //        select a dvd region for the user
01214     //
01215     
01216     cddata->DvdRpc0Device = FALSE;
01217 
01218     //
01219     // since StartIo() will call IoStartNextPacket() on error, allowing
01220     // StartIo() to be non-recursive prevents stack overflow bugchecks in
01221     // severe error cases (such as fault-injection in the verifier).
01222     //
01223     // the only difference is that the thread context may be different
01224     // in StartIo() than in the caller of IoStartNextPacket().
01225     //
01226 
01227     IoSetStartIoAttributes(Fdo, TRUE, TRUE);
01228 
01229     //
01230     // check to see if we have a DVD device
01231     //
01232 
01233     if (CdRomGetDeviceType(Fdo) != FILE_DEVICE_DVD) {
01234         return STATUS_SUCCESS;
01235     }
01236 
01237     //
01238     // we got a DVD drive.
01239     // now, figure out if we have a RPC0 device
01240     //
01241 
01242     bufferLen = DVD_RPC_KEY_LENGTH;
01243     copyProtectKey =
01244         (PDVD_COPY_PROTECT_KEY)ExAllocatePoolWithTag(PagedPool,
01245                                                      bufferLen,
01246                                                      DVD_TAG_RPC2_CHECK);
01247 
01248     if (copyProtectKey == NULL) {
01249         return STATUS_INSUFFICIENT_RESOURCES;
01250     }
01251 
01252     //
01253     // get the device region
01254     //
01255     RtlZeroMemory (copyProtectKey, bufferLen);
01256     copyProtectKey->KeyLength = DVD_RPC_KEY_LENGTH;
01257     copyProtectKey->KeyType = DvdGetRpcKey;
01258 
01259     //
01260     // Build a request for READ_KEY
01261     //
01262     ClassSendDeviceIoControlSynchronous(
01263         IOCTL_DVD_READ_KEY,
01264         Fdo,
01265         copyProtectKey,
01266         DVD_RPC_KEY_LENGTH,
01267         DVD_RPC_KEY_LENGTH,
01268         FALSE,
01269         &ioStatus
01270         );
01271 
01272     if (!NT_SUCCESS(ioStatus.Status)) {
01273 
01274         //
01275         // we have a rpc0 device
01276         //
01277         // NOTE: THIS MODIFIES THE BEHAVIOR OF THE IOCTL
01278         //
01279 
01280         cddata->DvdRpc0Device = TRUE;
01281 
01282         TraceLog((CdromDebugWarning,
01283                     "CdromStartDevice (%p): RPC Phase 1 drive detected\n",
01284                     Fdo));
01285 
01286         //
01287         // note: we could force this chosen now, but it's better to reduce
01288         // the number of code paths that could be taken.  always delay to
01289         // increase the percentage code coverage.
01290         //
01291 
01292         TraceLog((CdromDebugWarning,
01293                   "CdromStartDevice (%p): Delay DVD Region Selection\n",
01294                   Fdo));
01295 
01296         cddata->Rpc0SystemRegion           = 0xff;
01297         cddata->Rpc0SystemRegionResetCount = DVD_MAX_REGION_RESET_COUNT;
01298         cddata->PickDvdRegion              = 1;
01299         cddata->Rpc0RetryRegistryCallback  = 1;
01300         ExFreePool(copyProtectKey);
01301         return STATUS_SUCCESS;
01302 
01303     } else {
01304 
01305         rpcKey = (PDVD_RPC_KEY) copyProtectKey->KeyData;
01306 
01307         //
01308         // TypeCode of zero means that no region has been set.
01309         //
01310 
01311         if (rpcKey->TypeCode == 0) {
01312             TraceLog((CdromDebugWarning,
01313                         "CdromStartDevice (%p): must choose DVD region\n",
01314                         Fdo));
01315             cddata->PickDvdRegion = 1;
01316             CdRomPickDvdRegion(Fdo);
01317         }
01318     }
01319 
01320     ExFreePool (copyProtectKey);
01321 
01322     return STATUS_SUCCESS;
01323 }
01324 
01325 
01326 NTSTATUS
01327 CdRomStopDevice(
01328     IN PDEVICE_OBJECT DeviceObject,
01329     IN UCHAR Type
01330     )
01331 {
01332     return STATUS_SUCCESS;
01333 }
01334 
01335 
01336 VOID
01337 CdRomStartIo(
01338     IN PDEVICE_OBJECT Fdo,
01339     IN PIRP Irp
01340     )
01341 {
01342 
01343     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
01344     PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
01345 
01346     PIO_STACK_LOCATION  currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
01347     PIO_STACK_LOCATION  nextIrpStack = IoGetNextIrpStackLocation(Irp);
01348     PIO_STACK_LOCATION  irpStack;
01349 
01350     PIRP                irp2 = NULL;
01351 
01352     ULONG               transferPages;
01353     ULONG               transferByteCount = currentIrpStack->Parameters.Read.Length;
01354     LARGE_INTEGER       startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
01355     PCDROM_DATA         cdData;
01356     PSCSI_REQUEST_BLOCK srb = NULL;
01357     PCDB                cdb;
01358     PUCHAR              senseBuffer = NULL;
01359     PVOID               dataBuffer;
01360     NTSTATUS            status;
01361     BOOLEAN             use6Byte;
01362 
01363     //
01364     // Mark IRP with status pending.
01365     //
01366 
01367     IoMarkIrpPending(Irp);
01368 
01369     cdData = (PCDROM_DATA)(fdoExtension->CommonExtension.DriverData);
01370     use6Byte = TEST_FLAG(cdData->XAFlags, XA_USE_6_BYTE);
01371 
01372     //
01373     // if this test is true, then we will exit the routine within this
01374     // code block, queueing the irp for later completion.
01375     //
01376 
01377     if ((cdData->Mmc.IsMmc) &&
01378         (cdData->Mmc.UpdateState != CdromMmcUpdateComplete)
01379         ) {
01380 
01381         USHORT queueDepth;
01382         KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
01383                    "CdRomStartIo: [%p] Device needs to update capabilities\n",
01384                    Irp));
01385         ASSERT(cdData->Mmc.IsMmc);
01386         ASSERT(cdData->Mmc.CapabilitiesIrp != NULL);
01387         ASSERT(cdData->Mmc.CapabilitiesIrp != Irp);
01388 
01389         //
01390         // NOTE - REF #0002
01391         //
01392         // the state was either UpdateRequired (which means we will
01393         // have to start the work item) or UpdateStarted (which means
01394         // we have already started the work item at least once -- may
01395         // transparently change to UpdateComplete).
01396         //
01397         // if it's update required, we just queue it, change to UpdateStarted,
01398         // start the workitem, and start the next packet.
01399         //
01400         // else, we must queue the item and check the queue depth.  if the
01401         // queue depth is equal to 1, that means the worker item from the
01402         // previous attempt has already de-queued the items, so we should
01403         // call this routine again (retry) as an optimization rather than
01404         // re-add it this irp to the queue.  since this is tail recursion,
01405         // it won't take much/any stack to do this.
01406         //
01407         // NOTE: This presumes the following items are true:
01408         //
01409         // we only add to the list from CdRomStartIo(), which is serialized.
01410         // we only set to UpdateStarted from CdRomStartIo(), and only if
01411         //    the state was UpdateRequired.
01412         // we only set to UpdateRequired from CdRomMmcErrorHandler(), and
01413         //    only if the state was UpdateComplete.
01414         // we only set to UpdateComplete from the workitem, and assert the
01415         //    state was UpdateStarted.
01416         // we flush the entire queue in one atomic operation in the workitem,
01417         //    except in the special case described above when we dequeue
01418         //    the request immediately.
01419         //
01420         // order of operations is vitally important: queue, then test the depth
01421         // this will prevent lost irps.
01422         //
01423 
01424         ExInterlockedPushEntrySList(&(cdData->Mmc.DelayedIrps),
01425                                     (PSINGLE_LIST_ENTRY)&(Irp->Tail.Overlay.DriverContext[0]),
01426                                     &(cdData->Mmc.DelayedLock));
01427         
01428         queueDepth = ExQueryDepthSList(&(cdData->Mmc.DelayedIrps));
01429         if (queueDepth == 1) {
01430 
01431             if (cdData->Mmc.UpdateState == CdromMmcUpdateRequired) {
01432                 LONG oldState;
01433                 
01434                 //
01435                 // should free any old partition list info that
01436                 // we've previously saved away and then start the WorkItem
01437                 //
01438 
01439                 oldState = InterlockedExchange(&cdData->Mmc.UpdateState,
01440                                                CdromMmcUpdateStarted);
01441                 ASSERT(oldState == CdromMmcUpdateRequired);
01442 
01443                 IoQueueWorkItem(cdData->Mmc.CapabilitiesWorkItem,
01444                                 CdRomUpdateMmcDriveCapabilities,
01445                                 DelayedWorkQueue,
01446                                 NULL);
01447 
01448             } else {
01449                 
01450                 //
01451                 // they *just* finished updating, so we should flush the list
01452                 // back onto the StartIo queue and start the next packet.
01453                 //
01454 
01455                 CdRompFlushDelayedList(Fdo, &(cdData->Mmc), STATUS_SUCCESS, FALSE);
01456 
01457             }
01458 
01459         }
01460             
01461         //
01462         // start the next packet so we don't deadlock....
01463         //
01464 
01465         IoStartNextPacket(Fdo, FALSE);
01466         return;
01467     
01468     }
01469 
01470     //
01471     // If the flag is set in the device object
01472     // force a verify for READ, WRITE and RAW_READ requests
01473     // Note that ioctls are passed through....
01474     //
01475 
01476     if (TEST_FLAG(Fdo->Flags, DO_VERIFY_VOLUME) &&
01477         IS_READ_WRITE_REQUEST(currentIrpStack)) {
01478         
01479         TraceLog((CdromDebugTrace,
01480                     "CdRomStartIo: [%p] Volume needs verified\n", Irp));
01481         
01482         if (!(currentIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME)) {
01483 
01484             if (Irp->Tail.Overlay.Thread) {
01485                 IoSetHardErrorOrVerifyDevice(Irp, Fdo);
01486             }
01487 
01488             Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
01489 
01490             TraceLog((CdromDebugTrace,
01491                         "CdRomStartIo: [%p] Calling UpdateCapcity - "
01492                         "ioctl event = %p\n",
01493                         Irp,
01494                         nextIrpStack->Parameters.Others.Argument1
01495                       ));
01496 
01497             //
01498             // our device control dispatch routine stores an event in the next
01499             // stack location to signal when startio has completed.  We need to
01500             // pass this in so that the update capacity completion routine can
01501             // set it rather than completing the Irp.
01502             //
01503 
01504             status = CdRomUpdateCapacity(fdoExtension,
01505                                          Irp,
01506                                          nextIrpStack->Parameters.Others.Argument1
01507                                          );
01508 
01509             TraceLog((CdromDebugTrace,
01510                         "CdRomStartIo: [%p] UpdateCapacity returned %lx\n",
01511                         Irp, status));
01512             return;
01513         }
01514     }
01515 
01516     //
01517     // fail writes if they are not allowed...
01518     //
01519 
01520     if ((currentIrpStack->MajorFunction == IRP_MJ_WRITE) &&
01521         !(cdData->Mmc.WriteAllowed)) {
01522 
01523         TraceLog((CdromDebugError,
01524                     "CdRomStartIo: [%p] Device %p failing write request\n",
01525                     Irp, Fdo));
01526 
01527         Irp->IoStatus.Information = 0;
01528         Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
01529         BAIL_OUT(Irp);
01530         CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
01531         return;
01532     }
01533 
01534     if (currentIrpStack->MajorFunction == IRP_MJ_READ ||
01535         currentIrpStack->MajorFunction == IRP_MJ_WRITE ) {
01536 
01537         ULONG maximumTransferLength = fdoExtension->AdapterDescriptor->MaximumTransferLength;
01538 
01539         //
01540         // Add partition byte offset to make starting byte relative to
01541         // beginning of disk.
01542         //
01543 
01544         currentIrpStack->Parameters.Read.ByteOffset.QuadPart +=
01545             (fdoExtension->CommonExtension.StartingOffset.QuadPart);
01546 
01547         //
01548         // Calculate number of pages in this transfer.
01549         //
01550 
01551         transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress),
01552                                                        currentIrpStack->Parameters.Read.Length);
01553 
01554         //
01555         // Check if request length is greater than the maximum number of
01556         // bytes that the hardware can transfer.
01557         //
01558 
01559         if (cdData->RawAccess) {
01560 
01561             //
01562             // a writable device must be MMC compliant, which supports
01563             // READ_CD commands.
01564             //
01565 
01566             ASSERT(currentIrpStack->MajorFunction != IRP_MJ_WRITE);
01567 
01568             ASSERT(!TEST_FLAG(cdData->XAFlags, XA_USE_READ_CD));
01569 
01570             //
01571             // Fire off a mode select to switch back to cooked sectors.
01572             //
01573 
01574             irp2 = IoAllocateIrp((CCHAR)(Fdo->StackSize+1), FALSE);
01575 
01576             if (!irp2) {
01577                 Irp->IoStatus.Information = 0;
01578                 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
01579 
01580                 BAIL_OUT(Irp);
01581                 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
01582                 return;
01583             }
01584 
01585             srb = ExAllocatePoolWithTag(NonPagedPool,
01586                                         sizeof(SCSI_REQUEST_BLOCK),
01587                                         CDROM_TAG_SRB);
01588             if (!srb) {
01589                 IoFreeIrp(irp2);
01590                 Irp->IoStatus.Information = 0;
01591                 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
01592 
01593                 BAIL_OUT(Irp);
01594                 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
01595                 return;
01596             }
01597 
01598             RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
01599 
01600             cdb = (PCDB)srb->Cdb;
01601 
01602             //
01603             // Allocate sense buffer.
01604             //
01605 
01606             senseBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
01607                                                 SENSE_BUFFER_SIZE,
01608                                                 CDROM_TAG_SENSE_INFO);
01609 
01610             if (!senseBuffer) {
01611                 ExFreePool(srb);
01612                 IoFreeIrp(irp2);
01613                 Irp->IoStatus.Information = 0;
01614                 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
01615 
01616                 BAIL_OUT(Irp);
01617                 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
01618                 return;
01619             }
01620 
01621             //
01622             // Set up the irp.
01623             //
01624 
01625             IoSetNextIrpStackLocation(irp2);
01626             irp2->IoStatus.Status = STATUS_SUCCESS;
01627             irp2->IoStatus.Information = 0;
01628             irp2->Flags = 0;
01629             irp2->UserBuffer = NULL;
01630 
01631             //
01632             // Save the device object and irp in a private stack location.
01633             //
01634 
01635             irpStack = IoGetCurrentIrpStackLocation(irp2);
01636             irpStack->DeviceObject = Fdo;
01637             irpStack->Parameters.Others.Argument2 = (PVOID) Irp;
01638 
01639             //
01640             // The retry count will be in the real Irp, as the retry logic will
01641             // recreate our private irp.
01642             //
01643 
01644             if (!(nextIrpStack->Parameters.Others.Argument1)) {
01645 
01646                 //
01647                 // Only jam this in if it doesn't exist. The completion routines can
01648                 // call StartIo directly in the case of retries and resetting it will
01649                 // cause infinite loops.
01650                 //
01651 
01652                 nextIrpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
01653             }
01654 
01655             //
01656             // Construct the IRP stack for the lower level driver.
01657             //
01658 
01659             irpStack = IoGetNextIrpStackLocation(irp2);
01660             irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
01661             irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
01662             irpStack->Parameters.Scsi.Srb = srb;
01663 
01664             srb->Length = SCSI_REQUEST_BLOCK_SIZE;
01665             srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
01666             srb->SrbStatus = srb->ScsiStatus = 0;
01667             srb->NextSrb = 0;
01668             srb->OriginalRequest = irp2;
01669             srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
01670             srb->SenseInfoBuffer = senseBuffer;
01671 
01672             transferByteCount = (use6Byte) ? sizeof(ERROR_RECOVERY_DATA) : sizeof(ERROR_RECOVERY_DATA10);
01673 
01674             dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
01675                                                transferByteCount,
01676                                                CDROM_TAG_RAW);
01677 
01678             if (!dataBuffer) {
01679                 ExFreePool(senseBuffer);
01680                 ExFreePool(srb);
01681                 IoFreeIrp(irp2);
01682                 Irp->IoStatus.Information = 0;
01683                 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
01684 
01685                 BAIL_OUT(Irp);
01686                 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
01687                 return;
01688 
01689             }
01690 
01691             irp2->MdlAddress = IoAllocateMdl(dataBuffer,
01692                                             transferByteCount,
01693                                             FALSE,
01694                                             FALSE,
01695                                             (PIRP) NULL);
01696 
01697             if (!irp2->MdlAddress) {
01698                 ExFreePool(senseBuffer);
01699                 ExFreePool(srb);
01700                 ExFreePool(dataBuffer);
01701                 IoFreeIrp(irp2);
01702                 Irp->IoStatus.Information = 0;
01703                 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
01704 
01705                 BAIL_OUT(Irp);
01706                 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
01707                 return;
01708             }
01709 
01710             //
01711             // Prepare the MDL
01712             //
01713 
01714             MmBuildMdlForNonPagedPool(irp2->MdlAddress);
01715 
01716             srb->DataBuffer = dataBuffer;
01717 
01718             //
01719             // Set the new block size in the descriptor.
01720             //
01721 
01722             if (use6Byte) {
01723                 cdData->BlockDescriptor.BlockLength[0] = (UCHAR)(COOKED_SECTOR_SIZE >> 16) & 0xFF;
01724                 cdData->BlockDescriptor.BlockLength[1] = (UCHAR)(COOKED_SECTOR_SIZE >>  8) & 0xFF;
01725                 cdData->BlockDescriptor.BlockLength[2] = (UCHAR)(COOKED_SECTOR_SIZE & 0xFF);
01726             } else {
01727                 cdData->BlockDescriptor10.BlockLength[0] = (UCHAR)(COOKED_SECTOR_SIZE >> 16) & 0xFF;
01728                 cdData->BlockDescriptor10.BlockLength[1] = (UCHAR)(COOKED_SECTOR_SIZE >>  8) & 0xFF;
01729                 cdData->BlockDescriptor10.BlockLength[2] = (UCHAR)(COOKED_SECTOR_SIZE & 0xFF);
01730             }
01731 
01732             //
01733             // Move error page into dataBuffer.
01734             //
01735 
01736             RtlCopyMemory(srb->DataBuffer, &cdData->Header, transferByteCount);
01737 
01738             //
01739             // Build and send a mode select to switch into raw mode.
01740             //
01741 
01742             srb->SrbFlags = fdoExtension->SrbFlags;
01743             SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
01744             SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_OUT);
01745             srb->DataTransferLength = transferByteCount;
01746             srb->TimeOutValue = fdoExtension->TimeOutValue * 2;
01747 
01748             if (use6Byte) {
01749                 srb->CdbLength = 6;
01750                 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
01751                 cdb->MODE_SELECT.PFBit = 1;
01752                 cdb->MODE_SELECT.ParameterListLength = (UCHAR)transferByteCount;
01753             } else {
01754                 srb->CdbLength = 10;
01755                 cdb->MODE_SELECT10.OperationCode = SCSIOP_MODE_SELECT10;
01756                 cdb->MODE_SELECT10.PFBit = 1;
01757                 cdb->MODE_SELECT10.ParameterListLength[0] = (UCHAR)(transferByteCount >> 8);
01758                 cdb->MODE_SELECT10.ParameterListLength[1] = (UCHAR)(transferByteCount & 0xFF);
01759             }
01760 
01761             //
01762             // Update completion routine.
01763             //
01764 
01765             IoSetCompletionRoutine(irp2,
01766                                    CdRomSwitchModeCompletion,
01767                                    srb,
01768                                    TRUE,
01769                                    TRUE,
01770                                    TRUE);
01771 
01772             IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
01773             return;
01774         }
01775 
01776 
01777         //
01778         // Request needs to be split. Completion of each portion of the
01779         // request will fire off the next portion. The final request will
01780         // signal Io to send a new request.
01781         //
01782 
01783         transferPages =
01784             fdoExtension->AdapterDescriptor->MaximumPhysicalPages - 1;
01785 
01786         if(maximumTransferLength > (transferPages << PAGE_SHIFT)) {
01787             maximumTransferLength = transferPages << PAGE_SHIFT;
01788         }
01789 
01790         //
01791         // Check that the maximum transfer size is not zero
01792         //
01793 
01794         if(maximumTransferLength == 0) {
01795             maximumTransferLength = PAGE_SIZE;
01796         }
01797 
01798         ClassSplitRequest(Fdo, Irp, maximumTransferLength);
01799         return;
01800 
01801     } else if (currentIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
01802 
01803         //
01804         // Allocate an irp, srb and associated structures.
01805         //
01806 
01807         irp2 = IoAllocateIrp((CCHAR)(Fdo->StackSize+1),
01808                               FALSE);
01809 
01810         if (!irp2) {
01811             Irp->IoStatus.Information = 0;
01812             Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
01813 
01814             BAIL_OUT(Irp);
01815             CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
01816             return;
01817         }
01818 
01819         srb = ExAllocatePoolWithTag(NonPagedPool,
01820                                     sizeof(SCSI_REQUEST_BLOCK),
01821                                     CDROM_TAG_SRB);
01822         if (!srb) {
01823             IoFreeIrp(irp2);
01824             Irp->IoStatus.Information = 0;
01825             Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
01826 
01827             BAIL_OUT(Irp);
01828             CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
01829             return;
01830         }
01831 
01832         RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
01833 
01834         cdb = (PCDB)srb->Cdb;
01835 
01836         //
01837         // Allocate sense buffer.
01838         //
01839 
01840         senseBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
01841                                             SENSE_BUFFER_SIZE,
01842                                             CDROM_TAG_SENSE_INFO);
01843 
01844         if (!senseBuffer) {
01845             ExFreePool(srb);
01846             IoFreeIrp(irp2);
01847             Irp->IoStatus.Information = 0;
01848             Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
01849 
01850             BAIL_OUT(Irp);
01851             CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
01852             return;
01853         }
01854 
01855         RtlZeroMemory(senseBuffer, SENSE_BUFFER_SIZE);
01856 
01857         //
01858         // Set up the irp.
01859         //
01860 
01861         IoSetNextIrpStackLocation(irp2);
01862         irp2->IoStatus.Status = STATUS_SUCCESS;
01863         irp2->IoStatus.Information = 0;
01864         irp2->Flags = 0;
01865         irp2->UserBuffer = NULL;
01866 
01867         //
01868         // Save the device object and irp in a private stack location.
01869         //
01870 
01871         irpStack = IoGetCurrentIrpStackLocation(irp2);
01872         irpStack->DeviceObject = Fdo;
01873         irpStack->Parameters.Others.Argument2 = (PVOID) Irp;
01874 
01875         //
01876         // The retry count will be in the real Irp, as the retry logic will
01877         // recreate our private irp.
01878         //
01879 
01880         if (!(nextIrpStack->Parameters.Others.Argument1)) {
01881 
01882             //
01883             // Only jam this in if it doesn't exist. The completion routines can
01884             // call StartIo directly in the case of retries and resetting it will
01885             // cause infinite loops.
01886             //
01887 
01888             nextIrpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
01889         }
01890 
01891         //
01892         // keep track of the new irp as Argument3
01893         //
01894 
01895         nextIrpStack->Parameters.Others.Argument3 = irp2;
01896 
01897 
01898         //
01899         // Construct the IRP stack for the lower level driver.
01900         //
01901 
01902         irpStack = IoGetNextIrpStackLocation(irp2);
01903         irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
01904         irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
01905         irpStack->Parameters.Scsi.Srb = srb;
01906 
01907         IoSetCompletionRoutine(irp2,
01908                                CdRomDeviceControlCompletion,
01909                                srb,
01910                                TRUE,
01911                                TRUE,
01912                                TRUE);
01913         //
01914         // Setup those fields that are generic to all requests.
01915         //
01916 
01917         srb->Length = SCSI_REQUEST_BLOCK_SIZE;
01918         srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
01919         srb->SrbStatus = srb->ScsiStatus = 0;
01920         srb->NextSrb = 0;
01921         srb->OriginalRequest = irp2;
01922         srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
01923         srb->SenseInfoBuffer = senseBuffer;
01924 
01925         switch (currentIrpStack->Parameters.DeviceIoControl.IoControlCode) {
01926 
01927 
01928         case IOCTL_CDROM_RAW_READ: {
01929 
01930             //
01931             // Determine whether the drive is currently in raw or cooked mode,
01932             // and which command to use to read the data.
01933             //
01934 
01935             if (!TEST_FLAG(cdData->XAFlags, XA_USE_READ_CD)) {
01936 
01937                 PRAW_READ_INFO rawReadInfo =
01938                                    (PRAW_READ_INFO)currentIrpStack->Parameters.DeviceIoControl.Type3InputBuffer;
01939                 ULONG          maximumTransferLength;
01940                 ULONG          transferPages;
01941 
01942                 if (cdData->RawAccess) {
01943 
01944                     ULONG  startingSector;
01945                     UCHAR  min, sec, frame;
01946 
01947                     //
01948                     // Free the recently allocated irp, as we don't need it.
01949                     //
01950 
01951                     IoFreeIrp(irp2);
01952 
01953                     cdb = (PCDB)srb->Cdb;
01954                     RtlZeroMemory(cdb, CDB12GENERIC_LENGTH);
01955 
01956                     //
01957                     // Calculate starting offset.
01958                     //
01959 
01960                     startingSector = (ULONG)(rawReadInfo->DiskOffset.QuadPart >> fdoExtension->SectorShift);
01961                     transferByteCount  = rawReadInfo->SectorCount * RAW_SECTOR_SIZE;
01962                     maximumTransferLength = fdoExtension->AdapterDescriptor->MaximumTransferLength;
01963                     transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress),
01964                                                                    transferByteCount);
01965 
01966                     //
01967                     // Determine if request is within limits imposed by miniport.
01968                     //
01969                     if (transferByteCount > maximumTransferLength ||
01970                         transferPages > fdoExtension->AdapterDescriptor->MaximumPhysicalPages) {
01971 
01972                         //
01973                         // The claim is that this won't happen, and is backed up by
01974                         // ActiveMovie usage, which does unbuffered XA reads of 0x18000, yet
01975                         // we get only 4 sector requests.
01976                         //
01977 
01978                         ExFreePool(senseBuffer);
01979                         ExFreePool(srb);
01980 
01981                         Irp->IoStatus.Information = 0;
01982                         Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
01983 
01984                         BAIL_OUT(Irp);
01985                         CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
01986                         return;
01987 
01988                     }
01989 
01990                     srb->OriginalRequest = Irp;
01991                     srb->SrbFlags = fdoExtension->SrbFlags;
01992                     SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
01993                     SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
01994                     srb->DataTransferLength = transferByteCount;
01995                     srb->TimeOutValue = fdoExtension->TimeOutValue;
01996                     srb->CdbLength = 10;
01997                     srb->DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
01998 
01999                     if (rawReadInfo->TrackMode == CDDA) {
02000                         if (TEST_FLAG(cdData->XAFlags, XA_PLEXTOR_CDDA)) {
02001 
02002                             srb->CdbLength = 12;
02003 
02004                             cdb->PLXTR_READ_CDDA.LogicalBlockByte3  = (UCHAR) (startingSector & 0xFF);
02005                             cdb->PLXTR_READ_CDDA.LogicalBlockByte2  = (UCHAR) ((startingSector >>  8) & 0xFF);
02006                             cdb->PLXTR_READ_CDDA.LogicalBlockByte1  = (UCHAR) ((startingSector >> 16) & 0xFF);
02007                             cdb->PLXTR_READ_CDDA.LogicalBlockByte0  = (UCHAR) ((startingSector >> 24) & 0xFF);
02008 
02009                             cdb->PLXTR_READ_CDDA.TransferBlockByte3 = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
02010                             cdb->PLXTR_READ_CDDA.TransferBlockByte2 = (UCHAR) (rawReadInfo->SectorCount >> 8);
02011                             cdb->PLXTR_READ_CDDA.TransferBlockByte1 = 0;
02012                             cdb->PLXTR_READ_CDDA.TransferBlockByte0 = 0;
02013 
02014                             cdb->PLXTR_READ_CDDA.SubCode = 0;
02015                             cdb->PLXTR_READ_CDDA.OperationCode = 0xD8;
02016 
02017                         } else if (TEST_FLAG(cdData->XAFlags, XA_NEC_CDDA)) {
02018 
02019                             cdb->NEC_READ_CDDA.LogicalBlockByte3  = (UCHAR) (startingSector & 0xFF);
02020                             cdb->NEC_READ_CDDA.LogicalBlockByte2  = (UCHAR) ((startingSector >>  8) & 0xFF);
02021                             cdb->NEC_READ_CDDA.LogicalBlockByte1  = (UCHAR) ((startingSector >> 16) & 0xFF);
02022                             cdb->NEC_READ_CDDA.LogicalBlockByte0  = (UCHAR) ((startingSector >> 24) & 0xFF);
02023 
02024                             cdb->NEC_READ_CDDA.TransferBlockByte1 = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
02025                             cdb->NEC_READ_CDDA.TransferBlockByte0 = (UCHAR) (rawReadInfo->SectorCount >> 8);
02026 
02027                             cdb->NEC_READ_CDDA.OperationCode = 0xD4;
02028                         }
02029                     } else {
02030 
02031                         cdb->CDB10.TransferBlocksMsb  = (UCHAR) (rawReadInfo->SectorCount >> 8);
02032                         cdb->CDB10.TransferBlocksLsb  = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
02033 
02034                         cdb->CDB10.LogicalBlockByte3  = (UCHAR) (startingSector & 0xFF);
02035                         cdb->CDB10.LogicalBlockByte2  = (UCHAR) ((startingSector >>  8) & 0xFF);
02036                         cdb->CDB10.LogicalBlockByte1  = (UCHAR) ((startingSector >> 16) & 0xFF);
02037                         cdb->CDB10.LogicalBlockByte0  = (UCHAR) ((startingSector >> 24) & 0xFF);
02038 
02039                         cdb->CDB10.OperationCode = SCSIOP_READ;
02040                     }
02041 
02042                     srb->SrbStatus = srb->ScsiStatus = 0;
02043 
02044                     nextIrpStack->MajorFunction = IRP_MJ_SCSI;
02045                     nextIrpStack->Parameters.Scsi.Srb = srb;
02046 
02047                     // HACKHACK - REF #0001
02048 
02049                     //
02050                     // Set up IoCompletion routine address.
02051                     //
02052 
02053                     IoSetCompletionRoutine(Irp,
02054                                            CdRomXACompletion,
02055                                            srb,
02056                                            TRUE,
02057                                            TRUE,
02058                                            TRUE);
02059 
02060                     IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, Irp);
02061                     return;
02062 
02063                 } else {
02064 
02065                     transferByteCount = (use6Byte) ? sizeof(ERROR_RECOVERY_DATA) : sizeof(ERROR_RECOVERY_DATA10);
02066                     dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
02067                                                        transferByteCount,
02068                                                        CDROM_TAG_RAW );
02069                     if (!dataBuffer) {
02070                         ExFreePool(senseBuffer);
02071                         ExFreePool(srb);
02072                         IoFreeIrp(irp2);
02073                         Irp->IoStatus.Information = 0;
02074                         Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
02075 
02076                         BAIL_OUT(Irp);
02077                         CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
02078                         return;
02079 
02080                     }
02081 
02082                     irp2->MdlAddress = IoAllocateMdl(dataBuffer,
02083                                                     transferByteCount,
02084                                                     FALSE,
02085                                                     FALSE,
02086                                                     (PIRP) NULL);
02087 
02088                     if (!irp2->MdlAddress) {
02089                         ExFreePool(senseBuffer);
02090                         ExFreePool(srb);
02091                         ExFreePool(dataBuffer);
02092                         IoFreeIrp(irp2);
02093                         Irp->IoStatus.Information = 0;
02094                         Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
02095 
02096                         BAIL_OUT(Irp);
02097                         CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
02098                         return;
02099                     }
02100 
02101                     //
02102                     // Prepare the MDL
02103                     //
02104 
02105                     MmBuildMdlForNonPagedPool(irp2->MdlAddress);
02106 
02107                     srb->DataBuffer = dataBuffer;
02108 
02109                     //
02110                     // Set the new block size in the descriptor.
02111                     // This will set the block read size to RAW_SECTOR_SIZE
02112                     // TODO: Set density code, based on operation
02113                     //
02114 
02115                     if (use6Byte) {
02116                         cdData->BlockDescriptor.BlockLength[0] = (UCHAR)(RAW_SECTOR_SIZE >> 16) & 0xFF;
02117                         cdData->BlockDescriptor.BlockLength[1] = (UCHAR)(RAW_SECTOR_SIZE >>  8) & 0xFF;
02118                         cdData->BlockDescriptor.BlockLength[2] = (UCHAR)(RAW_SECTOR_SIZE & 0xFF);
02119                         cdData->BlockDescriptor.DensityCode = 0;
02120                     } else {
02121                         cdData->BlockDescriptor10.BlockLength[0] = (UCHAR)(RAW_SECTOR_SIZE >> 16) & 0xFF;
02122                         cdData->BlockDescriptor10.BlockLength[1] = (UCHAR)(RAW_SECTOR_SIZE >>  8) & 0xFF;
02123                         cdData->BlockDescriptor10.BlockLength[2] = (UCHAR)(RAW_SECTOR_SIZE & 0xFF);
02124                         cdData->BlockDescriptor10.DensityCode = 0;
02125                     }
02126 
02127                     //
02128                     // Move error page into dataBuffer.
02129                     //
02130 
02131                     RtlCopyMemory(srb->DataBuffer, &cdData->Header, transferByteCount);
02132 
02133 
02134                     //
02135                     // Build and send a mode select to switch into raw mode.
02136                     //
02137 
02138                     srb->SrbFlags = fdoExtension->SrbFlags;
02139                     SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
02140                     SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_OUT);
02141                     srb->DataTransferLength = transferByteCount;
02142                     srb->TimeOutValue = fdoExtension->TimeOutValue * 2;
02143 
02144                     if (use6Byte) {
02145                         srb->CdbLength = 6;
02146                         cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
02147                         cdb->MODE_SELECT.PFBit = 1;
02148                         cdb->MODE_SELECT.ParameterListLength = (UCHAR)transferByteCount;
02149                     } else {
02150 
02151                         srb->CdbLength = 10;
02152                         cdb->MODE_SELECT10.OperationCode = SCSIOP_MODE_SELECT10;
02153                         cdb->MODE_SELECT10.PFBit = 1;
02154                         cdb->MODE_SELECT10.ParameterListLength[0] = (UCHAR)(transferByteCount >> 8);
02155                         cdb->MODE_SELECT10.ParameterListLength[1] = (UCHAR)(transferByteCount & 0xFF);
02156                     }
02157 
02158                     //
02159                     // Update completion routine.
02160                     //
02161 
02162                     IoSetCompletionRoutine(irp2,
02163                                            CdRomSwitchModeCompletion,
02164                                            srb,
02165                                            TRUE,
02166                                            TRUE,
02167                                            TRUE);
02168 
02169                 }
02170 
02171             } else {
02172 
02173                 PRAW_READ_INFO rawReadInfo =
02174                                    (PRAW_READ_INFO)currentIrpStack->Parameters.DeviceIoControl.Type3InputBuffer;
02175                 ULONG  startingSector;
02176 
02177                 //
02178                 // Free the recently allocated irp, as we don't need it.
02179                 //
02180 
02181                 IoFreeIrp(irp2);
02182 
02183                 cdb = (PCDB)srb->Cdb;
02184                 RtlZeroMemory(cdb, CDB12GENERIC_LENGTH);
02185 
02186 
02187                 //
02188                 // Calculate starting offset.
02189                 //
02190 
02191                 startingSector = (ULONG)(rawReadInfo->DiskOffset.QuadPart >> fdoExtension->SectorShift);
02192                 transferByteCount  = rawReadInfo->SectorCount * RAW_SECTOR_SIZE;
02193 
02194                 srb->OriginalRequest = Irp;
02195                 srb->SrbFlags = fdoExtension->SrbFlags;
02196                 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
02197                 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
02198                 srb->DataTransferLength = transferByteCount;
02199                 srb->TimeOutValue = fdoExtension->TimeOutValue;
02200                 srb->DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
02201                 srb->CdbLength = 12;
02202                 srb->SrbStatus = srb->ScsiStatus = 0;
02203 
02204                 //
02205                 // Fill in CDB fields.
02206                 //
02207 
02208                 cdb = (PCDB)srb->Cdb;
02209 
02210 
02211                 cdb->READ_CD.TransferBlocks[2]  = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
02212                 cdb->READ_CD.TransferBlocks[1]  = (UCHAR) (rawReadInfo->SectorCount >> 8 );
02213                 cdb->READ_CD.TransferBlocks[0]  = (UCHAR) (rawReadInfo->SectorCount >> 16);
02214 
02215 
02216                 cdb->READ_CD.StartingLBA[3]  = (UCHAR) (startingSector & 0xFF);
02217                 cdb->READ_CD.StartingLBA[2]  = (UCHAR) ((startingSector >>  8));
02218                 cdb->READ_CD.StartingLBA[1]  = (UCHAR) ((startingSector >> 16));
02219                 cdb->READ_CD.StartingLBA[0]  = (UCHAR) ((startingSector >> 24));
02220 
02221                 //
02222                 // Setup cdb depending upon the sector type we want.
02223                 //
02224 
02225                 switch (rawReadInfo->TrackMode) {
02226                 case CDDA:
02227 
02228                     cdb->READ_CD.ExpectedSectorType = CD_DA_SECTOR;
02229                     cdb->READ_CD.IncludeUserData = 1;
02230                     cdb->READ_CD.HeaderCode = 3;
02231                     cdb->READ_CD.IncludeSyncData = 1;
02232                     break;
02233 
02234                 case YellowMode2:
02235 
02236                     cdb->READ_CD.ExpectedSectorType = YELLOW_MODE2_SECTOR;
02237                     cdb->READ_CD.IncludeUserData = 1;
02238                     cdb->READ_CD.HeaderCode = 1;
02239                     cdb->READ_CD.IncludeSyncData = 1;
02240                     break;
02241 
02242                 case XAForm2:
02243 
02244                     cdb->READ_CD.ExpectedSectorType = FORM2_MODE2_SECTOR;
02245                     cdb->READ_CD.IncludeUserData = 1;
02246                     cdb->READ_CD.HeaderCode = 3;
02247                     cdb->READ_CD.IncludeSyncData = 1;
02248                     break;
02249 
02250                 default:
02251                     ExFreePool(senseBuffer);
02252                     ExFreePool(srb);
02253                     Irp->IoStatus.Information = 0;
02254                     Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
02255 
02256                     BAIL_OUT(Irp);
02257                     CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
02258                     return;
02259                 }
02260 
02261                 cdb->READ_CD.OperationCode = SCSIOP_READ_CD;
02262 
02263                 nextIrpStack->MajorFunction = IRP_MJ_SCSI;
02264                 nextIrpStack->Parameters.Scsi.Srb = srb;
02265 
02266                 // HACKHACK - REF #0001
02267 
02268                 //
02269                 // Set up IoCompletion routine address.
02270                 //
02271 
02272                 IoSetCompletionRoutine(Irp,
02273                                        CdRomXACompletion,
02274                                        srb,
02275                                        TRUE,
02276                                        TRUE,
02277                                        TRUE);
02278 
02279                 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, Irp);
02280                 return;
02281 
02282             }
02283 
02284             IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
02285             return;
02286         }
02287 
02288         //
02289         // the _EX version does the same thing on the front end
02290         //
02291 
02292         case IOCTL_DISK_GET_LENGTH_INFO:
02293         case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX:
02294         case IOCTL_DISK_GET_DRIVE_GEOMETRY:
02295         case IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX:
02296         case IOCTL_CDROM_GET_DRIVE_GEOMETRY: {
02297 
02298             //
02299             // Issue ReadCapacity to update device extension
02300             // with information for current media.
02301             //
02302 
02303             TraceLog((CdromDebugError,
02304                         "CdRomStartIo: Get drive geometry/length "
02305                         "info (%p)\n", Irp));
02306 
02307             //
02308             // setup remaining srb and cdb parameters.
02309             //
02310 
02311             srb->SrbFlags = fdoExtension->SrbFlags;
02312             SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
02313             SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
02314             srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
02315             srb->CdbLength = 10;
02316             srb->TimeOutValue = fdoExtension->TimeOutValue;
02317 
02318             dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
02319                                                sizeof(READ_CAPACITY_DATA),
02320                                                CDROM_TAG_READ_CAP);
02321             if (!dataBuffer) {
02322                 ExFreePool(senseBuffer);
02323                 ExFreePool(srb);
02324                 IoFreeIrp(irp2);
02325                 Irp->IoStatus.Information = 0;
02326                 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
02327 
02328                 BAIL_OUT(Irp);
02329                 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
02330                 return;
02331 
02332             }
02333 
02334             irp2->MdlAddress = IoAllocateMdl(dataBuffer,
02335                                             sizeof(READ_CAPACITY_DATA),
02336                                             FALSE,
02337                                             FALSE,
02338                                             (PIRP) NULL);
02339 
02340             if (!irp2->MdlAddress) {
02341                 ExFreePool(senseBuffer);
02342                 ExFreePool(srb);
02343                 ExFreePool(dataBuffer);
02344                 IoFreeIrp(irp2);
02345                 Irp->IoStatus.Information = 0;
02346                 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
02347 
02348                 BAIL_OUT(Irp);
02349                 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
02350                 return;
02351             }
02352 
02353             //
02354             // Prepare the MDL
02355             //
02356 
02357             MmBuildMdlForNonPagedPool(irp2->MdlAddress);
02358 
02359             srb->DataBuffer = dataBuffer;
02360             cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
02361 
02362             IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
02363             return;
02364         }
02365 
02366         case IOCTL_CDROM_GET_CONFIGURATION: {
02367 
02368             PGET_CONFIGURATION_IOCTL_INPUT inputBuffer;
02369             
02370             TraceLog((CdromDebugError,
02371                         "CdRomStartIo: Get configuration (%p)\n", Irp));
02372 
02373             if (!cdData->Mmc.IsMmc) {
02374                 ExFreePool(senseBuffer);
02375                 ExFreePool(srb);
02376                 IoFreeIrp(irp2);
02377                 Irp->IoStatus.Information = 0;
02378                 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
02379                 BAIL_OUT(Irp);
02380                 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
02381                 return;
02382             }
02383 
02384             transferByteCount = currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
02385             
02386             dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
02387                                                transferByteCount,
02388                                                CDROM_TAG_GET_CONFIG);
02389             if (!dataBuffer) {
02390                 ExFreePool(senseBuffer);
02391                 ExFreePool(srb);
02392                 IoFreeIrp(irp2);
02393                 Irp->IoStatus.Information = 0;
02394                 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
02395                 BAIL_OUT(Irp);
02396                 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
02397                 return;
02398             }
02399 
02400             irp2->MdlAddress = IoAllocateMdl(dataBuffer,
02401                                              transferByteCount,
02402                                              FALSE,
02403                                              FALSE,
02404                                              (PIRP) NULL);
02405             if (!irp2->MdlAddress) {
02406                 ExFreePool(dataBuffer);
02407                 ExFreePool(senseBuffer);
02408                 ExFreePool(srb);
02409                 IoFreeIrp(irp2);
02410                 Irp->IoStatus.Information = 0;
02411                 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
02412                 BAIL_OUT(Irp);
02413                 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
02414                 return;
02415             }
02416 
02417             MmBuildMdlForNonPagedPool(irp2->MdlAddress);
02418             
02419             //
02420             // setup remaining srb and cdb parameters
02421             //
02422 
02423             srb->SrbFlags = fdoExtension->SrbFlags;
02424             SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
02425             srb->DataTransferLength = transferByteCount;
02426             srb->CdbLength = 10;
02427             srb->TimeOutValue = fdoExtension->TimeOutValue;
02428             srb->DataBuffer = dataBuffer;
02429             
02430             cdb->GET_CONFIGURATION.OperationCode = SCSIOP_GET_CONFIGURATION;
02431             cdb->GET_CONFIGURATION.AllocationLength[0] = (UCHAR)(transferByteCount >> 8);
02432             cdb->GET_CONFIGURATION.AllocationLength[1] = (UCHAR)(transferByteCount & 0xff);
02433 
02434             inputBuffer = (PGET_CONFIGURATION_IOCTL_INPUT)Irp->AssociatedIrp.SystemBuffer;
02435             cdb->GET_CONFIGURATION.StartingFeature[0] = (UCHAR)(inputBuffer->Feature >> 8);
02436             cdb->GET_CONFIGURATION.StartingFeature[1] = (UCHAR)(inputBuffer->Feature & 0xff);
02437             cdb->GET_CONFIGURATION.RequestType        = (UCHAR)(inputBuffer->RequestType);
02438             
02439             IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
02440             return;
02441         }
02442 
02443         case IOCTL_DISK_VERIFY: {
02444             
02445             PVERIFY_INFORMATION verifyInfo = Irp->AssociatedIrp.SystemBuffer;
02446             LARGE_INTEGER byteOffset;
02447             ULONG         sectorOffset;
02448             USHORT        sectorCount;
02449 
02450             if (!cdData->Mmc.WriteAllowed) {
02451                 ExFreePool(senseBuffer);
02452                 ExFreePool(srb);
02453                 IoFreeIrp(irp2);
02454                 Irp->IoStatus.Information = 0;
02455                 Irp->IoStatus.Status = STATUS_MEDIA_WRITE_PROTECTED;
02456                 BAIL_OUT(Irp);
02457                 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
02458                 return;
02459             }
02460             //
02461             // Verify sectors
02462             //
02463 
02464             srb->CdbLength = 10;
02465 
02466             cdb->CDB10.OperationCode = SCSIOP_VERIFY;
02467 
02468             //
02469             // Add disk offset to starting sector.
02470             //
02471 
02472             byteOffset.QuadPart = commonExtension->StartingOffset.QuadPart +
02473                                   verifyInfo->StartingOffset.QuadPart;
02474 
02475             //
02476             // Convert byte offset to sector offset.
02477             //
02478 
02479             sectorOffset = (ULONG)(byteOffset.QuadPart >> fdoExtension->SectorShift);
02480 
02481             //
02482             // Convert ULONG byte count to USHORT sector count.
02483             //
02484 
02485             sectorCount = (USHORT)(verifyInfo->Length >> fdoExtension->SectorShift);
02486 
02487             //
02488             // Move little endian values into CDB in big endian format.
02489             //
02490 
02491             cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&sectorOffset)->Byte3;
02492             cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&sectorOffset)->Byte2;
02493             cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&sectorOffset)->Byte1;
02494             cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&sectorOffset)->Byte0;
02495 
02496             cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&sectorCount)->Byte1;
02497             cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&sectorCount)->Byte0;
02498 
02499             //
02500             // The verify command is used by the NT FORMAT utility and
02501             // requests are sent down for 5% of the volume size. The
02502             // request timeout value is calculated based on the number of
02503             // sectors verified.
02504             //
02505 
02506             srb->TimeOutValue = ((sectorCount + 0x7F) >> 7) *
02507                                 fdoExtension->TimeOutValue;
02508 
02509             IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
02510             return;
02511         }
02512 
02513         case IOCTL_STORAGE_CHECK_VERIFY:
02514         case IOCTL_DISK_CHECK_VERIFY:
02515         case IOCTL_CDROM_CHECK_VERIFY: {
02516 
02517             //
02518             // Since a test unit ready is about to be performed, reset the
02519             // timer value to decrease the opportunities for it to race with
02520             // this code.
02521             //
02522 
02523             ClassResetMediaChangeTimer(fdoExtension);
02524 
02525             //
02526             // Set up the SRB/CDB
02527             //
02528 
02529             srb->CdbLength = 6;
02530             cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
02531             srb->TimeOutValue = fdoExtension->TimeOutValue * 2;
02532             srb->SrbFlags = fdoExtension->SrbFlags;
02533             SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
02534             SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER);
02535 
02536 
02537             TraceLog((CdromDebugTrace,
02538                         "CdRomStartIo: [%p] Sending CHECK_VERIFY irp %p\n",
02539                         Irp, irp2));
02540             IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
02541             return;
02542         }
02543 
02544         case IOCTL_DVD_READ_STRUCTURE: {
02545 
02546             CdRomDeviceControlDvdReadStructure(Fdo, Irp, irp2, srb);
02547             return;
02548 
02549         }
02550 
02551         case IOCTL_DVD_END_SESSION: {
02552             CdRomDeviceControlDvdEndSession(Fdo, Irp, irp2, srb);
02553             return;
02554         }
02555 
02556         case IOCTL_DVD_START_SESSION:
02557         case IOCTL_DVD_READ_KEY: {
02558 
02559             CdRomDeviceControlDvdStartSessionReadKey(Fdo, Irp, irp2, srb);
02560             return;
02561 
02562         }
02563 
02564 
02565         case IOCTL_DVD_SEND_KEY:
02566         case IOCTL_DVD_SEND_KEY2: {
02567 
02568             CdRomDeviceControlDvdSendKey (Fdo, Irp, irp2, srb);
02569             return;
02570 
02571 
02572         }
02573 
02574         case IOCTL_CDROM_READ_TOC_EX: {
02575             
02576             PCDROM_READ_TOC_EX inputBuffer = Irp->AssociatedIrp.SystemBuffer;
02577 
02578             transferByteCount = currentIrpStack->Parameters.Read.Length;
02579 
02580             dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
02581                                                transferByteCount,
02582                                                CDROM_TAG_TOC);
02583             if (!dataBuffer) {
02584                 ExFreePool(senseBuffer);
02585                 ExFreePool(srb);
02586                 IoFreeIrp(irp2);
02587                 Irp->IoStatus.Information = 0;
02588                 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
02589 
02590                 BAIL_OUT(Irp);
02591                 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
02592                 return;
02593 
02594             }
02595 
02596             irp2->MdlAddress = IoAllocateMdl(dataBuffer,
02597                                             transferByteCount,
02598                                             FALSE,
02599                                             FALSE,
02600                                             (PIRP) NULL);
02601 
02602             if (!irp2->MdlAddress) {
02603                 ExFreePool(senseBuffer);
02604                 ExFreePool(srb);
02605                 ExFreePool(dataBuffer);
02606                 IoFreeIrp(irp2);
02607                 Irp->IoStatus.Information = 0;
02608                 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
02609 
02610                 BAIL_OUT(Irp);
02611                 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
02612                 return;
02613             }
02614 
02615             //
02616             // setup the request per user request
02617             // do validity checking in devctl dispatch, not here
02618             //
02619 
02620             cdb->READ_TOC.OperationCode = SCSIOP_READ_TOC;
02621             cdb->READ_TOC.Msf = inputBuffer->Msf;
02622             cdb->READ_TOC.Format2 = inputBuffer->Format;
02623             cdb->READ_TOC.StartingTrack = inputBuffer->SessionTrack;
02624             cdb->READ_TOC.AllocationLength[0] = (UCHAR)(transferByteCount >> 8);
02625             cdb->READ_TOC.AllocationLength[1] = (UCHAR)(transferByteCount & 0xff);
02626 
02627             //
02628             // Prepare the MDL
02629             //
02630 
02631             MmBuildMdlForNonPagedPool(irp2->MdlAddress);
02632 
02633             //
02634             // do the standard stuff....
02635             //
02636 
02637             srb->SrbFlags = fdoExtension->SrbFlags;
02638             SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
02639             SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
02640             srb->DataTransferLength = transferByteCount;
02641             srb->CdbLength = 10;
02642             srb->TimeOutValue = fdoExtension->TimeOutValue;
02643             srb->DataBuffer = dataBuffer;
02644 
02645             IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
02646             return;
02647         }
02648 
02649         case IOCTL_CDROM_GET_LAST_SESSION:
02650         case IOCTL_CDROM_READ_TOC: {
02651 
02652             if (currentIrpStack->Parameters.DeviceIoControl.IoControlCode == 
02653                 IOCTL_CDROM_GET_LAST_SESSION) {
02654 
02655                 //
02656                 // Set format to return first and last session numbers.
02657                 //
02658 
02659                 cdb->READ_TOC.Format = CDROM_READ_TOC_EX_FORMAT_SESSION;
02660 
02661             } else {
02662 
02663                 //
02664                 // Use MSF addressing
02665                 //
02666 
02667                 cdb->READ_TOC.Msf = 1;
02668 
02669             }
02670 
02671 
02672             transferByteCount =
02673                 currentIrpStack->Parameters.Read.Length >
02674                     sizeof(CDROM_TOC) ? sizeof(CDROM_TOC):
02675                     currentIrpStack->Parameters.Read.Length;
02676 
02677             //
02678             // Set size of TOC structure.
02679             //
02680 
02681             cdb->READ_TOC.AllocationLength[0] = (UCHAR) (transferByteCount >> 8);
02682             cdb->READ_TOC.AllocationLength[1] = (UCHAR) (transferByteCount & 0xFF);
02683 
02684             //
02685             // setup remaining srb and cdb parameters.
02686             //
02687 
02688             srb->SrbFlags = fdoExtension->SrbFlags;
02689             SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
02690             SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
02691             srb->DataTransferLength = transferByteCount;
02692             srb->CdbLength = 10;
02693             srb->TimeOutValue = fdoExtension->TimeOutValue;
02694 
02695             dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
02696                                                transferByteCount,
02697                                                CDROM_TAG_TOC);
02698             if (!dataBuffer) {
02699                 ExFreePool(senseBuffer);
02700                 ExFreePool(srb);
02701                 IoFreeIrp(irp2);
02702                 Irp->IoStatus.Information = 0;
02703                 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
02704 
02705                 BAIL_OUT(Irp);
02706                 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
02707                 return;
02708 
02709             }
02710 
02711             irp2->MdlAddress = IoAllocateMdl(dataBuffer,
02712                                             transferByteCount,
02713                                             FALSE,
02714                                             FALSE,
02715                                             (PIRP) NULL);
02716 
02717             if (!irp2->MdlAddress) {
02718                 ExFreePool(senseBuffer);
02719                 ExFreePool(srb);
02720                 ExFreePool(dataBuffer);
02721                 IoFreeIrp(irp2);
02722                 Irp->IoStatus.Information = 0;
02723                 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
02724 
02725                 BAIL_OUT(Irp);
02726                 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
02727                 return;
02728             }
02729 
02730             //
02731             // Prepare the MDL
02732             //
02733             
02734             MmBuildMdlForNonPagedPool(irp2->MdlAddress);
02735 
02736             srb->DataBuffer = dataBuffer;
02737             cdb->READ_TOC.OperationCode = SCSIOP_READ_TOC;
02738 
02739             IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
02740             return;
02741 
02742         }
02743 
02744         case IOCTL_CDROM_PLAY_AUDIO_MSF: {
02745 
02746             PCDROM_PLAY_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
02747 
02748             //
02749             // Set up the SRB/CDB
02750             //
02751 
02752             srb->CdbLength = 10;
02753             cdb->PLAY_AUDIO_MSF.OperationCode = SCSIOP_PLAY_AUDIO_MSF;
02754 
02755             cdb->PLAY_AUDIO_MSF.StartingM = inputBuffer->StartingM;
02756             cdb->PLAY_AUDIO_MSF.StartingS = inputBuffer->StartingS;
02757             cdb->PLAY_AUDIO_MSF.StartingF = inputBuffer->StartingF;
02758 
02759             cdb->PLAY_AUDIO_MSF.EndingM = inputBuffer->EndingM;
02760             cdb->PLAY_AUDIO_MSF.EndingS = inputBuffer->EndingS;
02761             cdb->PLAY_AUDIO_MSF.EndingF = inputBuffer->EndingF;
02762 
02763             srb->TimeOutValue = fdoExtension->TimeOutValue;
02764             srb->SrbFlags = fdoExtension->SrbFlags;
02765             SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
02766             SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER);
02767 
02768             IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
02769             return;
02770 
02771         }
02772 
02773         case IOCTL_CDROM_READ_Q_CHANNEL: {
02774 
02775             PSUB_Q_CHANNEL_DATA userChannelData =
02776                              Irp->AssociatedIrp.SystemBuffer;
02777             PCDROM_SUB_Q_DATA_FORMAT inputBuffer =
02778                              Irp->AssociatedIrp.SystemBuffer;
02779 
02780             //
02781             // Allocate buffer for subq channel information.
02782             //
02783 
02784             dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
02785                                                sizeof(SUB_Q_CHANNEL_DATA),
02786                                                CDROM_TAG_SUB_Q);
02787 
02788             if (!dataBuffer) {
02789                 ExFreePool(senseBuffer);
02790                 ExFreePool(srb);
02791                 IoFreeIrp(irp2);
02792                 Irp->IoStatus.Information = 0;
02793                 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
02794 
02795                 BAIL_OUT(Irp);
02796                 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
02797                 return;
02798 
02799             }
02800 
02801             irp2->MdlAddress = IoAllocateMdl(dataBuffer,
02802                                              sizeof(SUB_Q_CHANNEL_DATA),
02803                                              FALSE,
02804                                              FALSE,
02805                                              (PIRP) NULL);
02806 
02807             if (!irp2->MdlAddress) {
02808                 ExFreePool(senseBuffer);
02809                 ExFreePool(srb);
02810                 ExFreePool(dataBuffer);
02811                 IoFreeIrp(irp2);
02812                 Irp->IoStatus.Information = 0;
02813                 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
02814 
02815                 BAIL_OUT(Irp);
02816                 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
02817                 return;
02818             }
02819 
02820             //
02821             // Prepare the MDL
02822             //
02823 
02824             MmBuildMdlForNonPagedPool(irp2->MdlAddress);
02825 
02826             srb->DataBuffer = dataBuffer;
02827 
02828             //
02829             // Always logical unit 0, but only use MSF addressing
02830             // for IOCTL_CDROM_CURRENT_POSITION
02831             //
02832 
02833             if (inputBuffer->Format==IOCTL_CDROM_CURRENT_POSITION)
02834                 cdb->SUBCHANNEL.Msf = CDB_USE_MSF;
02835 
02836             //
02837             // Return subchannel data
02838             //
02839 
02840             cdb->SUBCHANNEL.SubQ = CDB_SUBCHANNEL_BLOCK;
02841 
02842             //
02843             // Specify format of informatin to return
02844             //
02845 
02846             cdb->SUBCHANNEL.Format = inputBuffer->Format;
02847 
02848             //
02849             // Specify which track to access (only used by Track ISRC reads)
02850             //
02851 
02852             if (inputBuffer->Format==IOCTL_CDROM_TRACK_ISRC) {
02853                 cdb->SUBCHANNEL.TrackNumber = inputBuffer->Track;
02854             }
02855 
02856             //
02857             // Set size of channel data -- however, this is dependent on
02858             // what information we are requesting (which Format)
02859             //
02860 
02861             switch( inputBuffer->Format ) {
02862 
02863                 case IOCTL_CDROM_CURRENT_POSITION:
02864                     transferByteCount = sizeof(SUB_Q_CURRENT_POSITION);
02865                     break;
02866 
02867                 case IOCTL_CDROM_MEDIA_CATALOG:
02868                     transferByteCount = sizeof(SUB_Q_MEDIA_CATALOG_NUMBER);
02869                     break;
02870 
02871                 case IOCTL_CDROM_TRACK_ISRC:
02872                     transferByteCount = sizeof(SUB_Q_TRACK_ISRC);
02873                     break;
02874             }
02875 
02876             cdb->SUBCHANNEL.AllocationLength[0] = (UCHAR) (transferByteCount >> 8);
02877             cdb->SUBCHANNEL.AllocationLength[1] = (UCHAR) (transferByteCount &  0xFF);
02878             cdb->SUBCHANNEL.OperationCode = SCSIOP_READ_SUB_CHANNEL;
02879             srb->SrbFlags = fdoExtension->SrbFlags;
02880             SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
02881             SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
02882             srb->DataTransferLength = transferByteCount;
02883             srb->CdbLength = 10;
02884             srb->TimeOutValue = fdoExtension->TimeOutValue;
02885 
02886             IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
02887             return;
02888 
02889         }
02890 
02891         case IOCTL_CDROM_PAUSE_AUDIO: {
02892 
02893             cdb->PAUSE_RESUME.OperationCode = SCSIOP_PAUSE_RESUME;
02894             cdb->PAUSE_RESUME.Action = CDB_AUDIO_PAUSE;
02895 
02896             srb->CdbLength = 10;
02897             srb->TimeOutValue = fdoExtension->TimeOutValue;
02898             srb->SrbFlags = fdoExtension->SrbFlags;
02899             SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
02900             SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER);
02901 
02902             IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
02903             return;
02904         }
02905 
02906         case IOCTL_CDROM_RESUME_AUDIO: {
02907 
02908             cdb->PAUSE_RESUME.OperationCode = SCSIOP_PAUSE_RESUME;
02909             cdb->PAUSE_RESUME.Action = CDB_AUDIO_RESUME;
02910 
02911             srb->CdbLength = 10;
02912             srb->TimeOutValue = fdoExtension->TimeOutValue;
02913             srb->SrbFlags = fdoExtension->SrbFlags;
02914             SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
02915             SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER);
02916 
02917             IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
02918             return;
02919         }
02920 
02921         case IOCTL_CDROM_SEEK_AUDIO_MSF: {
02922 
02923             PCDROM_SEEK_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
02924             ULONG                 logicalBlockAddress;
02925 
02926             logicalBlockAddress = MSF_TO_LBA(inputBuffer->M, inputBuffer->S, inputBuffer->F);
02927 
02928             cdb->SEEK.OperationCode      = SCSIOP_SEEK;
02929             cdb->SEEK.LogicalBlockAddress[0] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte3;
02930             cdb->SEEK.LogicalBlockAddress[1] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte2;
02931             cdb->SEEK.LogicalBlockAddress[2] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte1;
02932             cdb->SEEK.LogicalBlockAddress[3] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte0;
02933 
02934             srb->CdbLength = 10;
02935             srb->TimeOutValue = fdoExtension->TimeOutValue;
02936             srb->SrbFlags = fdoExtension->SrbFlags;
02937             SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
02938             SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER);
02939 
02940             IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
02941             return;
02942 
02943         }
02944 
02945         case IOCTL_CDROM_STOP_AUDIO: {
02946 
02947             cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
02948             cdb->START_STOP.Immediate = 1;
02949             cdb->START_STOP.Start = 0;
02950             cdb->START_STOP.LoadEject = 0;
02951 
02952             srb->CdbLength = 6;
02953             srb->TimeOutValue = fdoExtension->TimeOutValue;
02954 
02955             srb->SrbFlags = fdoExtension->SrbFlags;
02956             SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
02957             SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER);
02958 
02959             IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
02960             return;
02961         }
02962 
02963         case IOCTL_CDROM_GET_CONTROL: {
02964 
02965             PAUDIO_OUTPUT audioOutput;
02966             PCDROM_AUDIO_CONTROL audioControl = Irp->AssociatedIrp.SystemBuffer;
02967 
02968             //
02969             // Allocate buffer for volume control information.
02970             //
02971 
02972             dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
02973                                                MODE_DATA_SIZE,
02974                                                CDROM_TAG_VOLUME);
02975 
02976             if (!dataBuffer) {
02977                 ExFreePool(senseBuffer);
02978                 ExFreePool(srb);
02979                 IoFreeIrp(irp2);
02980                 Irp->IoStatus.Information = 0;
02981                 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
02982 
02983                 BAIL_OUT(Irp);
02984                 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
02985                 return;
02986 
02987             }
02988 
02989             irp2->MdlAddress = IoAllocateMdl(dataBuffer,
02990                                             MODE_DATA_SIZE,
02991                                             FALSE,
02992                                             FALSE,
02993                                             (PIRP) NULL);
02994 
02995             if (!irp2->MdlAddress) {
02996                 ExFreePool(senseBuffer);
02997                 ExFreePool(srb);
02998                 ExFreePool(dataBuffer);
02999                 IoFreeIrp(irp2);
03000                 Irp->IoStatus.Information = 0;
03001                 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
03002 
03003                 BAIL_OUT(Irp);
03004                 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
03005                 return;
03006             }
03007 
03008             //
03009             // Prepare the MDL
03010             //
03011 
03012             MmBuildMdlForNonPagedPool(irp2->MdlAddress);
03013             srb->DataBuffer = dataBuffer;
03014 
03015             RtlZeroMemory(dataBuffer, MODE_DATA_SIZE);
03016 
03017             //
03018             // Setup for either 6 or 10 byte CDBs.
03019             //
03020 
03021             if (use6Byte) {
03022 
03023                 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
03024                 cdb->MODE_SENSE.PageCode = CDROM_AUDIO_CONTROL_PAGE;
03025                 cdb->MODE_SENSE.AllocationLength = MODE_DATA_SIZE;
03026 
03027                 //
03028                 // Disable block descriptors.
03029                 //
03030 
03031                 cdb->MODE_SENSE.Dbd = TRUE;
03032 
03033                 srb->CdbLength = 6;
03034             } else {
03035 
03036                 cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
03037                 cdb->MODE_SENSE10.PageCode = CDROM_AUDIO_CONTROL_PAGE;
03038                 cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(MODE_DATA_SIZE >> 8);
03039                 cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(MODE_DATA_SIZE & 0xFF);
03040 
03041                 //
03042                 // Disable block descriptors.
03043                 //
03044 
03045                 cdb->MODE_SENSE10.Dbd = TRUE;
03046 
03047                 srb->CdbLength = 10;
03048             }
03049 
03050             srb->TimeOutValue = fdoExtension->TimeOutValue;
03051             srb->DataTransferLength = MODE_DATA_SIZE;
03052             srb->SrbFlags = fdoExtension->SrbFlags;
03053             SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
03054             SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
03055 
03056             IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
03057             return;
03058 
03059         }
03060 
03061         case IOCTL_CDROM_GET_VOLUME:
03062         case IOCTL_CDROM_SET_VOLUME: {
03063 
03064             dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
03065                                         MODE_DATA_SIZE,
03066                                         CDROM_TAG_VOLUME);
03067 
03068             if (!dataBuffer) {
03069                 ExFreePool(senseBuffer);
03070                 ExFreePool(srb);
03071                 IoFreeIrp(irp2);
03072                 Irp->IoStatus.Information = 0;
03073                 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
03074 
03075                 BAIL_OUT(Irp);
03076                 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
03077                 return;
03078             }
03079 
03080             irp2->MdlAddress = IoAllocateMdl(dataBuffer,
03081                                             MODE_DATA_SIZE,
03082                                             FALSE,
03083                                             FALSE,
03084                                             (PIRP) NULL);
03085 
03086             if (!irp2->MdlAddress) {
03087                 ExFreePool(senseBuffer);
03088                 ExFreePool(srb);
03089                 ExFreePool(dataBuffer);
03090                 IoFreeIrp(irp2);
03091                 Irp->IoStatus.Information = 0;
03092                 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
03093 
03094                 BAIL_OUT(Irp);
03095                 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
03096                 return;
03097             }
03098 
03099             //
03100             // Prepare the MDL
03101             //
03102 
03103             MmBuildMdlForNonPagedPool(irp2->MdlAddress);
03104             srb->DataBuffer = dataBuffer;
03105 
03106             RtlZeroMemory(dataBuffer, MODE_DATA_SIZE);
03107 
03108 
03109             if (use6Byte) {
03110                 
03111                 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
03112                 cdb->MODE_SENSE.PageCode = CDROM_AUDIO_CONTROL_PAGE;
03113                 cdb->MODE_SENSE.AllocationLength = MODE_DATA_SIZE;
03114 
03115                 srb->CdbLength = 6;
03116 
03117             } else {
03118 
03119                 cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
03120                 cdb->MODE_SENSE10.PageCode = CDROM_AUDIO_CONTROL_PAGE;
03121                 cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(MODE_DATA_SIZE >> 8);
03122                 cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(MODE_DATA_SIZE & 0xFF);
03123 
03124                 srb->CdbLength = 10;
03125             }
03126 
03127             srb->TimeOutValue = fdoExtension->TimeOutValue;
03128             srb->DataTransferLength = MODE_DATA_SIZE;
03129             srb->SrbFlags = fdoExtension->SrbFlags;
03130             SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
03131             SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
03132 
03133             if (currentIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_SET_VOLUME) {
03134 
03135                 //
03136                 // Setup a different completion routine as the mode sense data is needed in order
03137                 // to send the mode select.
03138                 //
03139 
03140                 IoSetCompletionRoutine(irp2,
03141                                        CdRomSetVolumeIntermediateCompletion,
03142                                        srb,
03143                                        TRUE,
03144                                        TRUE,
03145                                        TRUE);
03146 
03147             }
03148 
03149             IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
03150             return;
03151 
03152         }
03153 
03154         case IOCTL_STORAGE_SET_READ_AHEAD: {
03155 
03156             PSTORAGE_SET_READ_AHEAD readAhead = Irp->AssociatedIrp.SystemBuffer;
03157 
03158             ULONG blockAddress;
03159             PFOUR_BYTE fourByte = (PFOUR_BYTE) &blockAddress;
03160 
03161             //
03162             // setup the SRB for a set readahead command
03163             //
03164 
03165             cdb->SET_READ_AHEAD.OperationCode = SCSIOP_SET_READ_AHEAD;
03166 
03167             blockAddress = (ULONG) (readAhead->TriggerAddress.QuadPart >>
03168                                     fdoExtension->SectorShift);
03169 
03170             cdb->SET_READ_AHEAD.TriggerLBA[0] = fourByte->Byte3;
03171             cdb->SET_READ_AHEAD.TriggerLBA[1] = fourByte->Byte2;
03172             cdb->SET_READ_AHEAD.TriggerLBA[2] = fourByte->Byte1;
03173             cdb->SET_READ_AHEAD.TriggerLBA[3] = fourByte->Byte0;
03174 
03175             blockAddress = (ULONG) (readAhead->TargetAddress.QuadPart >>
03176                                     fdoExtension->SectorShift);
03177 
03178             cdb->SET_READ_AHEAD.ReadAheadLBA[0] = fourByte->Byte3;
03179             cdb->SET_READ_AHEAD.ReadAheadLBA[1] = fourByte->Byte2;
03180             cdb->SET_READ_AHEAD.ReadAheadLBA[2] = fourByte->Byte1;
03181             cdb->SET_READ_AHEAD.ReadAheadLBA[3] = fourByte->Byte0;
03182 
03183             srb->CdbLength = 12;
03184             srb->TimeOutValue = fdoExtension->TimeOutValue;
03185 
03186             srb->SrbFlags = fdoExtension->SrbFlags;
03187             SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
03188             SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER);
03189 
03190             IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
03191             return;
03192         }
03193 
03194         case IOCTL_DISK_GET_DRIVE_LAYOUT:
03195         case IOCTL_DISK_GET_DRIVE_LAYOUT_EX:
03196         case IOCTL_DISK_GET_PARTITION_INFO:
03197         case IOCTL_DISK_GET_PARTITION_INFO_EX: {
03198 
03199             ASSERT(irp2);
03200             ASSERT(senseBuffer);
03201             ASSERT(srb);
03202 
03203             ExFreePool(srb);
03204             ExFreePool(senseBuffer);
03205             IoFreeIrp(irp2);
03206 
03207             //
03208             // NOTE: should probably update the media's capacity first...
03209             //
03210             
03211             CdromFakePartitionInfo(commonExtension, Irp);
03212             return;
03213         }
03214 
03215         case IOCTL_DISK_IS_WRITABLE: {
03216             
03217             TraceLog((CdromDebugWarning,
03218                         "CdRomStartIo: DiskIsWritable (%p) - returning %s\n",
03219                         Irp, (cdData->Mmc.WriteAllowed ? "TRUE" : "false")));
03220             
03221             ASSERT(irp2);
03222             ASSERT(senseBuffer);
03223             ASSERT(srb);
03224 
03225             ExFreePool(srb);
03226             ExFreePool(senseBuffer);
03227             IoFreeIrp(irp2);
03228 
03229             Irp->IoStatus.Information = 0;
03230             if (cdData->Mmc.WriteAllowed) {
03231                 Irp->IoStatus.Status = STATUS_SUCCESS;
03232             } else {
03233                 Irp->IoStatus.Status = STATUS_MEDIA_WRITE_PROTECTED;
03234             }
03235             CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
03236             return;
03237         }
03238 
03239         default: {
03240 
03241             UCHAR uniqueAddress;
03242 
03243             //
03244             // Just complete the request - CdRomClassIoctlCompletion will take
03245             // care of it for us 
03246             //
03247             // NOTE: THIS IS A SYNCHRONIZATION METHOD!!!
03248             //
03249 
03250             //
03251             // Acquire a new copy of the lock so that ClassCompleteRequest
03252             // doesn't get confused when we complete the other request while
03253             // holding the lock.
03254             //
03255 
03256             //
03257             // NOTE: CdRomDeviceControlDispatch/CdRomDeviceControlCompletion
03258             //       wait for the event and eventually calls
03259             //       IoStartNextPacket()
03260             //
03261 
03262             ASSERT(irp2);
03263             ASSERT(senseBuffer);
03264             ASSERT(srb);
03265 
03266             ExFreePool(srb);
03267             ExFreePool(senseBuffer);
03268             IoFreeIrp(irp2);
03269 
03270 
03271 
03272             ClassAcquireRemoveLock(Fdo, (PIRP)&uniqueAddress);
03273             ClassReleaseRemoveLock(Fdo, Irp);
03274             ClassCompleteRequest(Fdo, Irp, IO_NO_INCREMENT);
03275             ClassReleaseRemoveLock(Fdo, (PIRP)&uniqueAddress);
03276             return;
03277         }
03278 
03279         } // end switch()
03280     } else if (currentIrpStack->MajorFunction == IRP_MJ_SHUTDOWN ||
03281                currentIrpStack->MajorFunction == IRP_MJ_FLUSH_BUFFERS) {
03282 
03283         currentIrpStack->Parameters.Others.Argument1 = 0;
03284         Irp->IoStatus.Status = STATUS_SUCCESS;
03285         CdRomShutdownFlushCompletion(Fdo, NULL, Irp);
03286         return;
03287 
03288     }
03289 
03290     //
03291     // If a read or an unhandled IRP_MJ_XX, end up here. The unhandled IRP_MJ's
03292     // are expected and composed of AutoRun Irps, at present.
03293     //
03294 
03295     IoCallDriver(commonExtension->LowerDeviceObject, Irp);
03296     return;
03297 }
03298 
03299 
03300 NTSTATUS
03301 CdRomReadWriteVerification(
03302     IN PDEVICE_OBJECT DeviceObject,
03303     IN PIRP Irp
03304     )
03305 
03306 /*++
03307 
03308 Routine Description:
03309 
03310     This is the entry called by the I/O system for read requests.
03311     It builds the SRB and sends it to the port driver.
03312 
03313 Arguments:
03314 
03315     DeviceObject - the system object for the device.
03316     Irp - IRP involved.
03317 
03318 Return Value:
03319 
03320     NT Status
03321 
03322 --*/
03323 
03324 {
03325     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
03326     PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
03327 
03328     PIO_STACK_LOCATION  currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
03329     ULONG               transferByteCount = currentIrpStack->Parameters.Read.Length;
03330     LARGE_INTEGER       startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
03331 
03332     PCDROM_DATA         cdData = (PCDROM_DATA)(commonExtension->DriverData);
03333 
03334     SCSI_REQUEST_BLOCK  srb;
03335     PCDB                cdb = (PCDB)srb.Cdb;
03336     NTSTATUS            status;
03337 
03338     PAGED_CODE();
03339 
03340     //
03341     // note: we are no longer failing write commands immediately
03342     //       they are now failed in StartIo based upon media ability
03343     //
03344 
03345     //
03346     // If the cd is playing music then reject this request.
03347     //
03348 
03349     if (PLAY_ACTIVE(fdoExtension)) {
03350         Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
03351         return STATUS_DEVICE_BUSY;
03352     }
03353 
03354     //
03355     // Verify parameters of this request.
03356     // Check that ending sector is on disc and
03357     // that number of bytes to transfer is a multiple of
03358     // the sector size.
03359     //
03360 
03361     startingOffset.QuadPart = currentIrpStack->Parameters.Read.ByteOffset.QuadPart +
03362                               transferByteCount;
03363 
03364     if (!fdoExtension->DiskGeometry.BytesPerSector) {
03365         fdoExtension->DiskGeometry.BytesPerSector = 2048;
03366     }
03367 
03368     if ((startingOffset.QuadPart > commonExtension->PartitionLength.QuadPart) ||
03369         (transferByteCount & (fdoExtension->DiskGeometry.BytesPerSector - 1))) {
03370 
03371         //
03372         // Fail request with status of invalid parameters.
03373         //
03374 
03375         Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
03376 
03377         return STATUS_INVALID_PARAMETER;
03378     }
03379 
03380 
03381     return STATUS_SUCCESS;
03382 
03383 } // end CdRomReadWriteVerification()
03384 
03385 
03386 NTSTATUS
03387 CdRomSwitchModeCompletion(
03388     IN PDEVICE_OBJECT DeviceObject,
03389     IN PIRP Irp,
03390     IN PVOID Context
03391     )
03392 {
03393     PIO_STACK_LOCATION  realIrpStack;
03394     PIO_STACK_LOCATION  realIrpNextStack;
03395     PIRP                realIrp = NULL;
03396     NTSTATUS            status;
03397     BOOLEAN             retry;
03398     PSCSI_REQUEST_BLOCK srb     = Context;
03399     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
03400     PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
03401     PCDROM_DATA         cdData = (PCDROM_DATA)(commonExtension->DriverData);
03402     PIO_STACK_LOCATION  irpStack = IoGetCurrentIrpStackLocation(Irp);
03403     BOOLEAN             use6Byte = TEST_FLAG(cdData->XAFlags, XA_USE_6_BYTE);
03404     ULONG retryCount;
03405 
03406     //
03407     // Extract the 'real' irp from the irpstack.
03408     //
03409 
03410     realIrp = (PIRP) irpStack->Parameters.Others.Argument2;
03411     realIrpStack = IoGetCurrentIrpStackLocation(realIrp);
03412     realIrpNextStack = IoGetNextIrpStackLocation(realIrp);
03413 
03414     //
03415     // Check SRB status for success of completing request.
03416     //
03417 
03418     if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
03419 
03420         ULONG retryInterval;
03421 
03422         TraceLog((CdromDebugTrace,
03423                     "CdRomSetVolumeIntermediateCompletion: Irp %p, Srb %p, Real Irp %p\n",
03424                     Irp,
03425                     srb,
03426                     realIrp));
03427 
03428         //
03429         // Release the queue if it is frozen.
03430         //
03431 
03432         if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
03433             ClassReleaseQueue(DeviceObject);
03434         }
03435 
03436 
03437         retry = ClassInterpretSenseInfo(DeviceObject,
03438                                         srb,
03439                                         irpStack->MajorFunction,
03440                                         irpStack->Parameters.DeviceIoControl.IoControlCode,
03441                                         MAXIMUM_RETRIES - ((ULONG)(ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1),
03442                                         &status,
03443                                         &retryInterval);
03444 
03445         //
03446         // If the status is verified required and the this request
03447         // should bypass verify required then retry the request.
03448         //
03449 
03450         if (realIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
03451             status == STATUS_VERIFY_REQUIRED) {
03452 
03453             status = STATUS_IO_DEVICE_ERROR;
03454             retry = TRUE;
03455         }
03456 
03457         //
03458         // get current retry count
03459         //
03460         retryCount = PtrToUlong(realIrpNextStack->Parameters.Others.Argument1);
03461 
03462         if (retry && retryCount) {
03463 
03464             //
03465             // decrement retryCount and update
03466             //
03467             realIrpNextStack->Parameters.Others.Argument1 = UlongToPtr(retryCount-1);
03468 
03469             if (((ULONG)(ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1)) {
03470 
03471                 //
03472                 // Retry request.
03473                 //
03474 
03475                 TraceLog((CdromDebugWarning,
03476                             "Retry request %p - Calling StartIo\n", Irp));
03477 
03478 
03479                 ExFreePool(srb->SenseInfoBuffer);
03480                 ExFreePool(srb->DataBuffer);
03481                 ExFreePool(srb);
03482                 if (Irp->MdlAddress) {
03483                     IoFreeMdl(Irp->MdlAddress);
03484                 }
03485 
03486                 IoFreeIrp(Irp);
03487 
03488                 //
03489                 // Call StartIo directly since IoStartNextPacket hasn't been called,
03490                 // the serialisation is still intact.
03491                 //
03492 
03493                 CdRomRetryRequest(fdoExtension,
03494                                   realIrp,
03495                                   retryInterval,
03496                                   FALSE);
03497 
03498                 return STATUS_MORE_PROCESSING_REQUIRED;
03499 
03500             }
03501 
03502             //
03503             // Exhausted retries. Fall through and complete the request with the appropriate status.
03504             //
03505         }
03506     } else {
03507 
03508         //
03509         // Set status for successful request.
03510         //
03511 
03512         status = STATUS_SUCCESS;
03513         
03514     }
03515 
03516     if (NT_SUCCESS(status)) {
03517 
03518         ULONG sectorSize, startingSector, transferByteCount;
03519         PCDB cdb;
03520 
03521         //
03522         // Update device ext. to show which mode we are currently using.
03523         //
03524 
03525         sectorSize =  cdData->BlockDescriptor.BlockLength[0] << 16;
03526         sectorSize |= (cdData->BlockDescriptor.BlockLength[1] << 8);
03527         sectorSize |= (cdData->BlockDescriptor.BlockLength[2]);
03528 
03529         cdData->RawAccess = (sectorSize == RAW_SECTOR_SIZE) ? TRUE : FALSE;
03530 
03531         //
03532         // Free the old data buffer, mdl.
03533         // reuse the SenseInfoBuffer and Srb
03534         //
03535 
03536         ExFreePool(srb->DataBuffer);
03537         IoFreeMdl(Irp->MdlAddress);
03538         IoFreeIrp(Irp);
03539 
03540         //
03541         // rebuild the srb.
03542         //
03543 
03544         cdb = (PCDB)srb->Cdb;
03545         RtlZeroMemory(cdb, CDB12GENERIC_LENGTH);
03546 
03547 
03548         if (cdData->RawAccess) {
03549 
03550             PRAW_READ_INFO rawReadInfo =
03551                                (PRAW_READ_INFO)realIrpStack->Parameters.DeviceIoControl.Type3InputBuffer;
03552 
03553             ULONG maximumTransferLength;
03554             ULONG transferPages;
03555             UCHAR min, sec, frame;
03556 
03557             //
03558             // Calculate starting offset.
03559             //
03560 
03561             startingSector = (ULONG)(rawReadInfo->DiskOffset.QuadPart >> fdoExtension->SectorShift);
03562             transferByteCount  = rawReadInfo->SectorCount * RAW_SECTOR_SIZE;
03563             maximumTransferLength = fdoExtension->AdapterDescriptor->MaximumTransferLength;
03564             transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(realIrp->MdlAddress),
03565                                                            transferByteCount);
03566 
03567             //
03568             // Determine if request is within limits imposed by miniport.
03569             // If the request is larger than the miniport's capabilities, split it.
03570             //
03571 
03572             if (transferByteCount > maximumTransferLength ||
03573                 transferPages > fdoExtension->AdapterDescriptor->MaximumPhysicalPages) {
03574 
03575 
03576                 ExFreePool(srb->SenseInfoBuffer);
03577                 ExFreePool(srb);
03578                 realIrp->IoStatus.Information = 0;
03579                 realIrp->IoStatus.Status = STATUS_INVALID_PARAMETER;
03580 
03581                 BAIL_OUT(realIrp);
03582                 CdRomCompleteIrpAndStartNextPacketSafely(DeviceObject, realIrp);
03583                 return STATUS_MORE_PROCESSING_REQUIRED;
03584             }
03585 
03586             srb->OriginalRequest = realIrp;
03587             srb->SrbFlags = fdoExtension->SrbFlags;
03588             SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
03589             SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
03590 
03591             srb->DataTransferLength = transferByteCount;
03592             srb->TimeOutValue = fdoExtension->TimeOutValue;
03593             srb->CdbLength = 10;
03594             srb->DataBuffer = MmGetMdlVirtualAddress(realIrp->MdlAddress);
03595 
03596             if (rawReadInfo->TrackMode == CDDA) {
03597                 if (TEST_FLAG(cdData->XAFlags, XA_PLEXTOR_CDDA)) {
03598 
03599                     srb->CdbLength = 12;
03600 
03601                     cdb->PLXTR_READ_CDDA.LogicalBlockByte3  = (UCHAR) (startingSector & 0xFF);
03602                     cdb->PLXTR_READ_CDDA.LogicalBlockByte2  = (UCHAR) ((startingSector >>  8) & 0xFF);
03603                     cdb->PLXTR_READ_CDDA.LogicalBlockByte1  = (UCHAR) ((startingSector >> 16) & 0xFF);
03604                     cdb->PLXTR_READ_CDDA.LogicalBlockByte0  = (UCHAR) ((startingSector >> 24) & 0xFF);
03605 
03606                     cdb->PLXTR_READ_CDDA.TransferBlockByte3 = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
03607                     cdb->PLXTR_READ_CDDA.TransferBlockByte2 = (UCHAR) (rawReadInfo->SectorCount >> 8);
03608                     cdb->PLXTR_READ_CDDA.TransferBlockByte1 = 0;
03609                     cdb->PLXTR_READ_CDDA.TransferBlockByte0 = 0;
03610 
03611                     cdb->PLXTR_READ_CDDA.SubCode = 0;
03612                     cdb->PLXTR_READ_CDDA.OperationCode = 0xD8;
03613 
03614                 } else if (TEST_FLAG(cdData->XAFlags, XA_NEC_CDDA)) {
03615 
03616                     cdb->NEC_READ_CDDA.LogicalBlockByte3  = (UCHAR) (startingSector & 0xFF);
03617                     cdb->NEC_READ_CDDA.LogicalBlockByte2  = (UCHAR) ((startingSector >>  8) & 0xFF);
03618                     cdb->NEC_READ_CDDA.LogicalBlockByte1  = (UCHAR) ((startingSector >> 16) & 0xFF);
03619                     cdb->NEC_READ_CDDA.LogicalBlockByte0  = (UCHAR) ((startingSector >> 24) & 0xFF);
03620 
03621                     cdb->NEC_READ_CDDA.TransferBlockByte1 = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
03622                     cdb->NEC_READ_CDDA.TransferBlockByte0 = (UCHAR) (rawReadInfo->SectorCount >> 8);
03623 
03624                     cdb->NEC_READ_CDDA.OperationCode = 0xD4;
03625                 }
03626             } else {
03627                 cdb->CDB10.TransferBlocksMsb  = (UCHAR) (rawReadInfo->SectorCount >> 8);
03628                 cdb->CDB10.TransferBlocksLsb  = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
03629 
03630                 cdb->CDB10.LogicalBlockByte3  = (UCHAR) (startingSector & 0xFF);
03631                 cdb->CDB10.LogicalBlockByte2  = (UCHAR) ((startingSector >>  8) & 0xFF);
03632                 cdb->CDB10.LogicalBlockByte1  = (UCHAR) ((startingSector >> 16) & 0xFF);
03633                 cdb->CDB10.LogicalBlockByte0  = (UCHAR) ((startingSector >> 24) & 0xFF);
03634 
03635                 cdb->CDB10.OperationCode = SCSIOP_READ;
03636             }
03637 
03638             srb->SrbStatus = srb->ScsiStatus = 0;
03639 
03640 
03641             irpStack = IoGetNextIrpStackLocation(realIrp);
03642             irpStack->MajorFunction = IRP_MJ_SCSI;
03643             irpStack->Parameters.Scsi.Srb = srb;
03644 
03645             if (!(irpStack->Parameters.Others.Argument1)) {
03646 
03647                 //
03648                 // Only jam this in if it doesn't exist. The completion routines can
03649                 // call StartIo directly in the case of retries and resetting it will
03650                 // cause infinite loops.
03651                 //
03652 
03653                 irpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
03654             }
03655 
03656             //
03657             // Set up IoCompletion routine address.
03658             //
03659 
03660             IoSetCompletionRoutine(realIrp,
03661                                    CdRomXACompletion,
03662                                    srb,
03663                                    TRUE,
03664                                    TRUE,
03665                                    TRUE);
03666         } else {
03667 
03668             PSTORAGE_ADAPTER_DESCRIPTOR adapterDescriptor;
03669             ULONG maximumTransferLength;
03670             ULONG transferPages;
03671 
03672             //
03673             // a writable device must be MMC compliant, which supports
03674             // READ_CD commands, so writes and mode switching should
03675             // never occur on the same device.
03676             //
03677 
03678             ASSERT(realIrpStack->MajorFunction != IRP_MJ_WRITE);
03679 
03680             //
03681             // free the SRB and SenseInfoBuffer since they aren't used
03682             // by either ClassBuildRequest() nor ClassSplitRequest().
03683             //
03684 
03685             ExFreePool(srb->SenseInfoBuffer);
03686             ExFreePool(srb);
03687             
03688             //
03689             // Back to cooked sectors. Build and send a normal read.
03690             // The real work for setting offsets was done in startio.
03691             //
03692             
03693             adapterDescriptor =
03694                 commonExtension->PartitionZeroExtension->AdapterDescriptor;
03695             maximumTransferLength = adapterDescriptor->MaximumTransferLength;
03696             transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
03697                                 MmGetMdlVirtualAddress(realIrp->MdlAddress),
03698                                 realIrpStack->Parameters.Read.Length);
03699 
03700             if ((realIrpStack->Parameters.Read.Length > maximumTransferLength) ||
03701                 (transferPages > adapterDescriptor->MaximumPhysicalPages)) {
03702 
03703                 ULONG maxPages = adapterDescriptor->MaximumPhysicalPages;
03704 
03705                 if (maxPages != 0) {
03706                     maxPages --; // to account for page boundaries
03707                 }
03708 
03709                 TraceLog((CdromDebugTrace,
03710                             "CdromSwitchModeCompletion: Request greater than "
03711                             " maximum\n"));
03712                 TraceLog((CdromDebugTrace,
03713                             "CdromSwitchModeCompletion: Maximum is %lx\n",
03714                             maximumTransferLength));
03715                 TraceLog((CdromDebugTrace,
03716                             "CdromSwitchModeCompletion: Byte count is %lx\n",
03717                             realIrpStack->Parameters.Read.Length));
03718 
03719                 //
03720                 // Check that the maximum transfer length fits within
03721                 // the maximum number of pages the device can handle.
03722                 //
03723                 
03724                 if (maximumTransferLength > maxPages << PAGE_SHIFT) {
03725                     maximumTransferLength = maxPages << PAGE_SHIFT;
03726                 }
03727 
03728                 //
03729                 // Check that maximum transfer size is not zero
03730                 //
03731 
03732                 if (maximumTransferLength == 0) {
03733                     maximumTransferLength = PAGE_SIZE;
03734                 }
03735 
03736                 //
03737                 // Request needs to be split. Completion of each portion
03738                 // of the request will fire off the next portion. The final
03739                 // request will signal Io to send a new request.
03740                 //
03741 
03742                 ClassSplitRequest(DeviceObject, realIrp, maximumTransferLength);
03743                 return STATUS_MORE_PROCESSING_REQUIRED;
03744 
03745             } else {
03746 
03747                 //
03748                 // Build SRB and CDB for this IRP.
03749                 //
03750 
03751                 ClassBuildRequest(DeviceObject, realIrp);
03752 
03753             }
03754         }
03755 
03756         //
03757         // Call the port driver.
03758         //
03759 
03760         IoCallDriver(commonExtension->LowerDeviceObject, realIrp);
03761 
03762         return STATUS_MORE_PROCESSING_REQUIRED;
03763     }
03764 
03765     //
03766     // Update device Extension flags to indicate that XA isn't supported.
03767     //
03768 
03769     TraceLog((CdromDebugWarning,
03770                 "Device Cannot Support CDDA (but tested positive) "
03771                 "Now Clearing CDDA flags for FDO %p\n", DeviceObject));
03772     SET_FLAG(cdData->XAFlags, XA_NOT_SUPPORTED);
03773     CLEAR_FLAG(cdData->XAFlags, XA_PLEXTOR_CDDA);
03774     CLEAR_FLAG(cdData->XAFlags, XA_NEC_CDDA);
03775 
03776     //
03777     // Deallocate srb and sense buffer.
03778     //
03779 
03780     if (srb) {
03781         if (srb->DataBuffer) {
03782             ExFreePool(srb->DataBuffer);
03783         }
03784         if (srb->SenseInfoBuffer) {
03785             ExFreePool(srb->SenseInfoBuffer);
03786         }
03787         ExFreePool(srb);
03788     }
03789 
03790     if (Irp->PendingReturned) {
03791       IoMarkIrpPending(Irp);
03792     }
03793 
03794     if (realIrp->PendingReturned) {
03795         IoMarkIrpPending(realIrp);
03796     }
03797 
03798     if (Irp->MdlAddress) {
03799         IoFreeMdl(Irp->MdlAddress);
03800     }
03801 
03802     IoFreeIrp(Irp);
03803 
03804     //
03805     // Set status in completing IRP.
03806     //
03807 
03808     realIrp->IoStatus.Status = status;
03809 
03810     //
03811     // Set the hard error if necessary.
03812     //
03813 
03814     if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
03815 
03816         //
03817         // Store DeviceObject for filesystem, and clear
03818         // in IoStatus.Information field.
03819         //
03820 
03821         if (realIrp->Tail.Overlay.Thread) {
03822             IoSetHardErrorOrVerifyDevice(realIrp, DeviceObject);
03823         }
03824         realIrp->IoStatus.Information = 0;
03825     }
03826 
03827     CdRomCompleteIrpAndStartNextPacketSafely(DeviceObject, realIrp);
03828 
03829     return STATUS_MORE_PROCESSING_REQUIRED;
03830 }
03831 
03832 
03833 VOID
03834 ScanForSpecialHandler(
03835     PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
03836     ULONG_PTR HackFlags
03837     )
03838 {
03839     PCOMMON_DEVICE_EXTENSION commonExtension;
03840     PCDROM_DATA cdData;
03841 
03842     PAGED_CODE();
03843 
03844     CLEAR_FLAG(HackFlags, CDROM_HACK_INVALID_FLAGS);
03845     
03846     commonExtension = &(FdoExtension->CommonExtension);
03847     cdData = (PCDROM_DATA)(commonExtension->DriverData);
03848     cdData->HackFlags = HackFlags;
03849 
03850     return;
03851 }
03852 
03853 VOID
03854 ScanForSpecial(
03855     PDEVICE_OBJECT DeviceObject
03856     )
03857 
03858 /*++
03859 
03860 Routine Description:
03861 
03862     This function checks to see if an SCSI logical unit requires an special
03863     initialization or error processing.
03864 
03865 Arguments:
03866 
03867     DeviceObject - Supplies the device object to be tested.
03868 
03869     InquiryData - Supplies the inquiry data returned by the device of interest.
03870 
03871     PortCapabilities - Supplies the capabilities of the device object.
03872 
03873 Return Value:
03874 
03875     None.
03876 
03877 --*/
03878 
03879 {
03880     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
03881     PCOMMON_DEVICE_EXTENSION commonExtension;
03882     PCDROM_DATA cdData;
03883     
03884     PAGED_CODE();
03885 
03886     fdoExtension = DeviceObject->DeviceExtension;
03887     commonExtension = DeviceObject->DeviceExtension;
03888     cdData = (PCDROM_DATA)(commonExtension->DriverData);
03889 
03890     
03891     //
03892     // set our hack flags
03893     //
03894 
03895     ClassScanForSpecial(fdoExtension, CdromHackItems, ScanForSpecialHandler);
03896 
03897     //
03898     // All CDRom's can ignore the queue lock failure for power operations
03899     // and do not require handling the SpinUp case (unknown result of sending
03900     // a cdrom a START_UNIT command -- may eject disks?)
03901     //
03902     // We send the stop command mostly to stop outstanding asynch operations
03903     // (like audio playback) from running when the system is powered off.
03904     // Because of this and the unlikely chance that a PLAY command will be
03905     // sent in the window between the STOP and the time the machine powers down
03906     // we don't require queue locks.  This is important because without them
03907     // classpnp's power routines will send the START_STOP_UNIT command to the
03908     // device whether or not it supports locking (atapi does not support locking
03909     // and if we requested them we would end up not stopping audio on atapi
03910     // devices).
03911     //
03912 
03913     SET_FLAG(fdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_DISABLE_SPIN_UP);
03914     SET_FLAG(fdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_NO_QUEUE_LOCK);
03915 
03916     if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_HITACHI_1750)
03917         && ( fdoExtension->AdapterDescriptor->AdapterUsesPio )
03918         ) {
03919 
03920         //
03921         // Read-ahead must be disabled in order to get this cdrom drive
03922         // to work on scsi adapters that use PIO.
03923         //
03924 
03925 
03926         TraceLog((CdromDebugWarning,
03927                     "CdRom ScanForSpecial:  Found Hitachi CDR-1750S.\n"));
03928 
03929         //
03930         // Setup an error handler to reinitialize the cd rom after it is reset.
03931         //
03932 
03933         cdData->ErrorHandler = HitachiProcessError;
03934 
03935         //
03936         // Lock down the hitachi error processing code.
03937         //
03938 
03939         MmLockPagableCodeSection(HitachiProcessError);
03940         SET_FLAG(cdData->HackFlags, CDROM_HACK_LOCKED_PAGES);
03941 
03942 
03943     } else if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_TOSHIBA_SD_W1101)) {
03944 
03945         TraceLog((CdromDebugError,
03946                     "CdRom ScanForSpecial: Found Toshiba SD-W1101 DVD-RAM "
03947                     "-- This drive will *NOT* support DVD-ROM playback.\n"));
03948 
03949     } else if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_HITACHI_GD_2000)) {
03950 
03951         TraceLog((CdromDebugWarning,
03952                     "CdRom ScanForSpecial: Found Hitachi GD-2000\n"));
03953 
03954         //
03955         // Setup an error handler to spin up the drive when it idles out
03956         // since it seems to like to fail to spin itself back up on its
03957         // own for a REPORT_KEY command.  It may also lose the AGIDs that
03958         // it has given, which will result in DVD playback failures.
03959         // This routine will just do what it can...
03960         //
03961 
03962         cdData->ErrorHandler = HitachiProcessErrorGD2000;
03963 
03964         //
03965         // this drive may require START_UNIT commands to spin
03966         // the drive up when it's spun itself down.
03967         //
03968 
03969         SET_FLAG(fdoExtension->DeviceFlags, DEV_SAFE_START_UNIT);
03970 
03971         //
03972         // Lock down the hitachi error processing code.
03973         //
03974 
03975         MmLockPagableCodeSection(HitachiProcessErrorGD2000);
03976         SET_FLAG(cdData->HackFlags, CDROM_HACK_LOCKED_PAGES);
03977 
03978     } else if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_FUJITSU_FMCD_10x)) {
03979 
03980         //
03981         // When Read command is issued to FMCD-101 or FMCD-102 and there is a music
03982         // cd in it. It takes longer time than SCSI_CDROM_TIMEOUT before returning
03983         // error status.
03984         //
03985 
03986         fdoExtension->TimeOutValue = 20;
03987 
03988     } else if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_DEC_RRD)) {
03989 
03990         PMODE_PARM_READ_WRITE_DATA modeParameters;
03991         SCSI_REQUEST_BLOCK         srb;
03992         PCDB                       cdb;
03993         NTSTATUS                   status;
03994 
03995 
03996         TraceLog((CdromDebugWarning,
03997                     "CdRom ScanForSpecial:  Found DEC RRD.\n"));
03998 
03999         cdData->IsDecRrd = TRUE;
04000 
04001         //
04002         // Setup an error handler to reinitialize the cd rom after it is reset?
04003         //
04004         //commonExtension->DevInfo->ClassError = DecRrdProcessError;
04005 
04006         //
04007         // Found a DEC RRD cd-rom.  These devices do not pass MS HCT
04008         // multi-media tests because the DEC firmware modifieds the block
04009         // from the PC-standard 2K to 512.  Change the block transfer size
04010         // back to the PC-standard 2K by using a mode select command.
04011         //
04012 
04013         modeParameters = ExAllocatePoolWithTag(NonPagedPool,
04014                                                sizeof(MODE_PARM_READ_WRITE_DATA),
04015                                                CDROM_TAG_MODE_DATA
04016                                                );
04017         if (modeParameters == NULL) {
04018             return;
04019         }
04020 
04021         RtlZeroMemory(modeParameters, sizeof(MODE_PARM_READ_WRITE_DATA));
04022         RtlZeroMemory(&srb,           sizeof(SCSI_REQUEST_BLOCK));
04023 
04024         //
04025         // Set the block length to 2K.
04026         //
04027 
04028         modeParameters->ParameterListHeader.BlockDescriptorLength =
04029                 sizeof(MODE_PARAMETER_BLOCK);
04030 
04031         //
04032         // Set block length to 2K (0x0800) in Parameter Block.
04033         //
04034 
04035         modeParameters->ParameterListBlock.BlockLength[0] = 0x00; //MSB
04036         modeParameters->ParameterListBlock.BlockLength[1] = 0x08;
04037         modeParameters->ParameterListBlock.BlockLength[2] = 0x00; //LSB
04038 
04039         //
04040         // Build the mode select CDB.
04041         //
04042 
04043         srb.CdbLength = 6;
04044         srb.TimeOutValue = fdoExtension->TimeOutValue;
04045 
04046         cdb = (PCDB)srb.Cdb;
04047         cdb->MODE_SELECT.PFBit               = 1;
04048         cdb->MODE_SELECT.OperationCode       = SCSIOP_MODE_SELECT;
04049         cdb->MODE_SELECT.ParameterListLength = HITACHI_MODE_DATA_SIZE;
04050 
04051         //
04052         // Send the request to the device.
04053         //
04054 
04055         status = ClassSendSrbSynchronous(DeviceObject,
04056                                          &srb,
04057                                          modeParameters,
04058                                          sizeof(MODE_PARM_READ_WRITE_DATA),
04059                                          TRUE);
04060 
04061         if (!NT_SUCCESS(status)) {
04062             TraceLog((CdromDebugWarning,
04063                         "CdRom ScanForSpecial: Setting DEC RRD to 2K block"
04064                         "size failed [%x]\n", status));
04065         }
04066         ExFreePool(modeParameters);
04067 
04068     } else if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_TOSHIBA_XM_3xx)) {
04069 
04070         SCSI_REQUEST_BLOCK srb;
04071         PCDB               cdb;
04072         ULONG              length;
04073         PUCHAR             buffer;
04074         NTSTATUS           status;
04075 
04076         //
04077         // Set the density code and the error handler.
04078         //
04079 
04080         length = (sizeof(MODE_READ_RECOVERY_PAGE) + MODE_BLOCK_DESC_LENGTH + MODE_HEADER_LENGTH);
04081 
04082         RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
04083 
04084         //
04085         // Build the MODE SENSE CDB.
04086         //
04087 
04088         srb.CdbLength = 6;
04089         cdb = (PCDB)srb.Cdb;
04090 
04091         //
04092         // Set timeout value from device extension.
04093         //
04094 
04095         srb.TimeOutValue = fdoExtension->TimeOutValue;
04096 
04097         cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
04098         cdb->MODE_SENSE.PageCode = 0x1;
04099         // NOTE: purposely not setting DBD because it is what is needed.
04100         cdb->MODE_SENSE.AllocationLength = (UCHAR)length;
04101 
04102         buffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
04103                                 (sizeof(MODE_READ_RECOVERY_PAGE) + MODE_BLOCK_DESC_LENGTH + MODE_HEADER_LENGTH),
04104                                 CDROM_TAG_MODE_DATA);
04105         if (!buffer) {
04106             return;
04107         }
04108 
04109         status = ClassSendSrbSynchronous(DeviceObject,
04110                                          &srb,
04111                                          buffer,
04112                                          length,
04113                                          FALSE);
04114 
04115         ((PERROR_RECOVERY_DATA)buffer)->BlockDescriptor.DensityCode = 0x83;
04116         ((PERROR_RECOVERY_DATA)buffer)->Header.ModeDataLength = 0x0;
04117 
04118         RtlCopyMemory(&cdData->Header, buffer, sizeof(ERROR_RECOVERY_DATA));
04119 
04120         RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
04121 
04122         //
04123         // Build the MODE SENSE CDB.
04124         //
04125 
04126         srb.CdbLength = 6;
04127         cdb = (PCDB)srb.Cdb;
04128 
04129         //
04130         // Set timeout value from device extension.
04131         //
04132 
04133         srb.TimeOutValue = fdoExtension->TimeOutValue;
04134 
04135         cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
04136         cdb->MODE_SELECT.PFBit = 1;
04137         cdb->MODE_SELECT.ParameterListLength = (UCHAR)length;
04138 
04139         status = ClassSendSrbSynchronous(DeviceObject,
04140                                          &srb,
04141                                          buffer,
04142                                          length,
04143                                          TRUE);
04144 
04145         if (!NT_SUCCESS(status)) {
04146             TraceLog((CdromDebugWarning,
04147                         "Cdrom.ScanForSpecial: Setting density code on Toshiba failed [%x]\n",
04148                         status));
04149         }
04150 
04151         cdData->ErrorHandler = ToshibaProcessError;
04152 
04153         //
04154         // Lock down the toshiba error section.
04155         //
04156 
04157         MmLockPagableCodeSection(ToshibaProcessError);
04158         SET_FLAG(cdData->HackFlags, CDROM_HACK_LOCKED_PAGES);
04159 
04160         ExFreePool(buffer);
04161 
04162     }
04163 
04164     //
04165     // Determine special CD-DA requirements.
04166     //
04167 
04168     if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_READ_CD_SUPPORTED)) {
04169 
04170         SET_FLAG(cdData->XAFlags, XA_USE_READ_CD);
04171 
04172     } else if (!TEST_FLAG(cdData->XAFlags, XA_USE_READ_CD)) {
04173 
04174         if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_PLEXTOR_CDDA)) {
04175             SET_FLAG(cdData->XAFlags, XA_PLEXTOR_CDDA);
04176         } else if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_NEC_CDDA)) {
04177             SET_FLAG(cdData->XAFlags, XA_NEC_CDDA);
04178         }
04179 
04180     }
04181 
04182     if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_LOCKED_PAGES)) {
04183         KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_ERROR_LEVEL,
04184                    "Locking pages for error handler\n"));
04185     }
04186 
04187     
04188     return;
04189 }
04190 
04191 
04192 VOID
04193 HitachiProcessErrorGD2000(
04194     PDEVICE_OBJECT Fdo,
04195     PSCSI_REQUEST_BLOCK OriginalSrb,
04196     NTSTATUS *Status,
04197     BOOLEAN *Retry
04198     )
04199 /*++
04200 
04201 Routine Description:
04202 
04203    This routine checks the type of error.  If the error suggests that the
04204    drive has spun down and cannot reinitialize itself, send a
04205    START_UNIT or READ to the device.  This will force the drive to spin
04206    up.  This drive also loses the AGIDs it has granted when it spins down,
04207    which may result in playback failure the first time around.
04208 
04209 Arguments:
04210 
04211     DeviceObject - Supplies a pointer to the device object.
04212 
04213     Srb - Supplies a pointer to the failing Srb.
04214 
04215     Status - return the final status for this command?
04216 
04217     Retry - return if the command should be retried.
04218 
04219 Return Value:
04220 
04221     None.
04222 
04223 --*/
04224 {
04225     PSENSE_DATA         senseBuffer = OriginalSrb->SenseInfoBuffer;
04226 
04227     UNREFERENCED_PARAMETER(Status);
04228     UNREFERENCED_PARAMETER(Retry);
04229 
04230     if (!TEST_FLAG(OriginalSrb->SrbStatus, SRB_STATUS_AUTOSENSE_VALID)) {
04231         return;
04232     }
04233 
04234     if (((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_HARDWARE_ERROR) &&
04235         (senseBuffer->AdditionalSenseCode == 0x44)) {
04236 
04237         PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
04238         PIRP                irp;
04239         PIO_STACK_LOCATION  irpStack;
04240         PCOMPLETION_CONTEXT context;
04241         PSCSI_REQUEST_BLOCK newSrb;
04242         PCDB                cdb;
04243 
04244         TraceLog((CdromDebugWarning,
04245                     "HitachiProcessErrorGD2000 (%p) => Internal Target "
04246                     "Failure Detected -- spinning up drive\n", Fdo));
04247 
04248         //
04249         // the request should be retried because the device isn't ready
04250         //
04251 
04252         *Retry = TRUE;
04253         *Status = STATUS_DEVICE_NOT_READY;
04254 
04255         //
04256         // send a START_STOP unit to spin up the drive
04257         // NOTE: this temporarily violates the StartIo serialization
04258         //       mechanism, but the completion routine on this will NOT
04259         //       call StartNextPacket(), so it's a temporary disruption
04260         //       of the serialization only.
04261         //
04262 
04263         ClassSendStartUnit(Fdo);
04264 
04265     }
04266 
04267     return;
04268 }
04269 
04270 
04271 VOID
04272 HitachiProcessError(
04273     PDEVICE_OBJECT DeviceObject,
04274     PSCSI_REQUEST_BLOCK Srb,
04275     NTSTATUS *Status,
04276     BOOLEAN *Retry
04277     )
04278 /*++
04279 
04280 Routine Description:
04281 
04282    This routine checks the type of error.  If the error indicates CD-ROM the
04283    CD-ROM needs to be reinitialized then a Mode sense command is sent to the
04284    device.  This command disables read-ahead for the device.
04285 
04286 Arguments:
04287 
04288     DeviceObject - Supplies a pointer to the device object.
04289 
04290     Srb - Supplies a pointer to the failing Srb.
04291 
04292     Status - Not used.
04293 
04294     Retry - Not used.
04295 
04296 Return Value:
04297 
04298     None.
04299 
04300 --*/
04301 
04302 {
04303     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
04304     PSENSE_DATA         senseBuffer = Srb->SenseInfoBuffer;
04305     LARGE_INTEGER       largeInt;
04306     PUCHAR              modePage;
04307     PIO_STACK_LOCATION  irpStack;
04308     PIRP                irp;
04309     PSCSI_REQUEST_BLOCK srb;
04310     PCOMPLETION_CONTEXT context;
04311     PCDB                cdb;
04312     ULONG_PTR            alignment;
04313 
04314     UNREFERENCED_PARAMETER(Status);
04315     UNREFERENCED_PARAMETER(Retry);
04316 
04317     largeInt.QuadPart = (LONGLONG) 1;
04318 
04319     //
04320     // Check the status.  The initialization command only needs to be sent
04321     // if UNIT ATTENTION is returned.
04322     //
04323 
04324     if (!(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID)) {
04325 
04326         //
04327         // The drive does not require reinitialization.
04328         //
04329 
04330         return;
04331     }
04332 
04333     //
04334     // Found an HITACHI cd-rom that does not work with PIO
04335     // adapters when read-ahead is enabled.  Read-ahead is disabled by
04336     // a mode select command.  The mode select page code is zero and the
04337     // length is 6 bytes.  All of the other bytes should be zero.
04338     //
04339 
04340     if ((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_UNIT_ATTENTION) {
04341 
04342         TraceLog((CdromDebugWarning,
04343                     "HitachiProcessError: Reinitializing the CD-ROM.\n"));
04344 
04345         //
04346         // Send the special mode select command to disable read-ahead
04347         // on the CD-ROM reader.
04348         //
04349 
04350         alignment = DeviceObject->AlignmentRequirement ?
04351             DeviceObject->AlignmentRequirement : 1;
04352 
04353         context = ExAllocatePoolWithTag(
04354             NonPagedPool,
04355             sizeof(COMPLETION_CONTEXT) +  HITACHI_MODE_DATA_SIZE + (ULONG)alignment,
04356             CDROM_TAG_HITACHI_ERROR
04357             );
04358 
04359         if (context == NULL) {
04360 
04361             //
04362             // If there is not enough memory to fulfill this request,
04363             // simply return. A subsequent retry will fail and another
04364             // chance to start the unit.
04365             //
04366 
04367             return;
04368         }
04369 
04370         context->DeviceObject = DeviceObject;
04371         srb = &context->Srb;
04372 
04373         RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
04374 
04375         //
04376         // Write length to SRB.
04377         //
04378 
04379         srb->Length = SCSI_REQUEST_BLOCK_SIZE;
04380 
04381         //
04382         // Set up SCSI bus address.
04383         //
04384 
04385         srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
04386         srb->TimeOutValue = fdoExtension->TimeOutValue;
04387 
04388         //
04389         // Set the transfer length.
04390         //
04391 
04392         srb->DataTransferLength = HITACHI_MODE_DATA_SIZE;
04393         srb->SrbFlags = fdoExtension->SrbFlags;
04394         SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_OUT);
04395         SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_AUTOSENSE);
04396         SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
04397 
04398         //
04399         // The data buffer must be aligned.
04400         //
04401 
04402         srb->DataBuffer = (PVOID) (((ULONG_PTR) (context + 1) + (alignment - 1)) &
04403             ~(alignment - 1));
04404 
04405 
04406         //
04407         // Build the HITACHI read-ahead mode select CDB.
04408         //
04409 
04410         srb->CdbLength = 6;
04411         cdb = (PCDB)srb->Cdb;
04412         cdb->MODE_SENSE.LogicalUnitNumber = srb->Lun;
04413         cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SELECT;
04414         cdb->MODE_SENSE.AllocationLength = HITACHI_MODE_DATA_SIZE;
04415 
04416         //
04417         // Initialize the mode sense data.
04418         //
04419 
04420         modePage = srb->DataBuffer;
04421 
04422         RtlZeroMemory(modePage, HITACHI_MODE_DATA_SIZE);
04423 
04424         //
04425         // Set the page length field to 6.
04426         //
04427 
04428         modePage[5] = 6;
04429 
04430         //
04431         // Build the asynchronous request to be sent to the port driver.
04432         //
04433 
04434         irp = IoBuildAsynchronousFsdRequest(IRP_MJ_WRITE,
04435                                            DeviceObject,
04436                                            srb->DataBuffer,
04437                                            srb->DataTransferLength,
04438                                            &largeInt,
04439                                            NULL);
04440 
04441         if (irp == NULL) {
04442 
04443             //
04444             // If there is not enough memory to fulfill this request,
04445             // simply return. A subsequent retry will fail and another
04446             // chance to start the unit.
04447             //
04448 
04449             ExFreePool(context);
04450             return;
04451         }
04452 
04453         ClassAcquireRemoveLock(DeviceObject, irp);
04454 
04455         IoSetCompletionRoutine(irp,
04456                    (PIO_COMPLETION_ROUTINE)ClassAsynchronousCompletion,
04457                    context,
04458                    TRUE,
04459                    TRUE,
04460                    TRUE);
04461 
04462         irpStack = IoGetNextIrpStackLocation(irp);
04463 
04464         irpStack->MajorFunction = IRP_MJ_SCSI;
04465 
04466         srb->OriginalRequest = irp;
04467 
04468         //
04469         // Save SRB address in next stack for port driver.
04470         //
04471 
04472         irpStack->Parameters.Scsi.Srb = (PVOID)srb;
04473 
04474         //
04475         // Set up IRP Address.
04476         //
04477 
04478         (VOID)IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp);
04479 
04480     }
04481 }
04482 
04483 
04484 NTSTATUS
04485 ToshibaProcessErrorCompletion(
04486     PDEVICE_OBJECT DeviceObject,
04487     PIRP Irp,
04488     PVOID Context
04489     )
04490 
04491 /*++
04492 
04493 Routine Description:
04494 
04495     Completion routine for the ClassError routine to handle older Toshiba units
04496     that require setting the density code.
04497 
04498 Arguments:
04499 
04500     DeviceObject - Supplies a pointer to the device object.
04501 
04502     Irp - Pointer to irp created to set the density code.
04503 
04504     Context - Supplies a pointer to the Mode Select Srb.
04505 
04506 
04507 Return Value:
04508 
04509     STATUS_MORE_PROCESSING_REQUIRED
04510 
04511 --*/
04512 
04513 {
04514 
04515     PSCSI_REQUEST_BLOCK srb = Context;
04516 
04517     //
04518     // Free all of the allocations.
04519     //
04520 
04521     ClassReleaseRemoveLock(DeviceObject, Irp);
04522 
04523     ExFreePool(srb->DataBuffer);
04524     ExFreePool(srb);
04525     IoFreeMdl(Irp->MdlAddress);
04526     IoFreeIrp(Irp);
04527 
04528     //
04529     // Indicate the I/O system should stop processing the Irp completion.
04530     //
04531 
04532     return STATUS_MORE_PROCESSING_REQUIRED;
04533 }
04534 
04535 
04536 VOID
04537 ToshibaProcessError(
04538     PDEVICE_OBJECT DeviceObject,
04539     PSCSI_REQUEST_BLOCK Srb,
04540     NTSTATUS *Status,
04541     BOOLEAN *Retry
04542     )
04543 
04544 /*++
04545 
04546 Routine Description:
04547 
04548    This routine checks the type of error.  If the error indicates a unit attention,
04549    the density code needs to be set via a Mode select command.
04550 
04551 Arguments:
04552 
04553     DeviceObject - Supplies a pointer to the device object.
04554 
04555     Srb - Supplies a pointer to the failing Srb.
04556 
04557     Status - Not used.
04558 
04559     Retry - Not used.
04560 
04561 Return Value:
04562 
04563     None.
04564 
04565 --*/
04566 
04567 {
04568     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
04569     PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
04570 
04571     PCDROM_DATA         cdData = (PCDROM_DATA)(commonExtension->DriverData);
04572     PSENSE_DATA         senseBuffer = Srb->SenseInfoBuffer;
04573     PIO_STACK_LOCATION  irpStack;
04574     PIRP                irp;
04575     PSCSI_REQUEST_BLOCK srb;
04576     ULONG               length;
04577     PCDB                cdb;
04578     PUCHAR              dataBuffer;
04579 
04580 
04581     if (!(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID)) {
04582         return;
04583     }
04584 
04585     //
04586     // The Toshiba's require the density code to be set on power up and media changes.
04587     //
04588 
04589     if ((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_UNIT_ATTENTION) {
04590 
04591 
04592         irp = IoAllocateIrp((CCHAR)(DeviceObject->StackSize+1),
04593                               FALSE);
04594 
04595         if (!irp) {
04596             return;
04597         }
04598 
04599         srb = ExAllocatePoolWithTag(NonPagedPool,
04600                                     sizeof(SCSI_REQUEST_BLOCK),
04601                                     CDROM_TAG_TOSHIBA_ERROR);
04602         if (!srb) {
04603             IoFreeIrp(irp);
04604             return;
04605         }
04606 
04607 
04608         length = sizeof(ERROR_RECOVERY_DATA);
04609         dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
04610                                            length,
04611                                            CDROM_TAG_TOSHIBA_ERROR);
04612         if (!dataBuffer) {
04613             ExFreePool(srb);
04614             IoFreeIrp(irp);
04615             return;
04616         }
04617 
04618         irp->MdlAddress = IoAllocateMdl(dataBuffer,
04619                                         length,
04620                                         FALSE,
04621                                         FALSE,
04622                                         (PIRP) NULL);
04623 
04624         if (!irp->MdlAddress) {
04625             ExFreePool(srb);
04626             ExFreePool(dataBuffer);
04627             IoFreeIrp(irp);
04628             return;
04629         }
04630 
04631         //
04632         // Prepare the MDL
04633         //
04634 
04635         MmBuildMdlForNonPagedPool(irp->MdlAddress);
04636 
04637         RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
04638 
04639         srb->DataBuffer = dataBuffer;
04640         cdb = (PCDB)srb->Cdb;
04641 
04642         //
04643         // Set up the irp.
04644         //
04645 
04646         IoSetNextIrpStackLocation(irp);
04647         irp->IoStatus.Status = STATUS_SUCCESS;
04648         irp->IoStatus.Information = 0;
04649         irp->Flags = 0;
04650         irp->UserBuffer = NULL;
04651 
04652         //
04653         // Save the device object and irp in a private stack location.
04654         //
04655 
04656         irpStack = IoGetCurrentIrpStackLocation(irp);
04657         irpStack->DeviceObject = DeviceObject;
04658 
04659         //
04660         // Construct the IRP stack for the lower level driver.
04661         //
04662 
04663         irpStack = IoGetNextIrpStackLocation(irp);
04664         irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
04665         irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_OUT;
04666         irpStack->Parameters.Scsi.Srb = srb;
04667 
04668         IoSetCompletionRoutine(irp,
04669                                ToshibaProcessErrorCompletion,
04670                                srb,
04671                                TRUE,
04672                                TRUE,
04673                                TRUE);
04674 
04675         ClassAcquireRemoveLock(DeviceObject, irp);
04676 
04677         srb->Length = SCSI_REQUEST_BLOCK_SIZE;
04678         srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
04679         srb->SrbStatus = srb->ScsiStatus = 0;
04680         srb->NextSrb = 0;
04681         srb->OriginalRequest = irp;
04682         srb->SenseInfoBufferLength = 0;
04683 
04684         //
04685         // Set the transfer length.
04686         //
04687 
04688         srb->DataTransferLength = length;
04689         srb->SrbFlags = fdoExtension->SrbFlags;
04690         SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_OUT);
04691         SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_AUTOSENSE);
04692         SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
04693         SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE);
04694 
04695 
04696         srb->CdbLength = 6;
04697         cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
04698         cdb->MODE_SELECT.PFBit = 1;
04699         cdb->MODE_SELECT.ParameterListLength = (UCHAR)length;
04700 
04701         //
04702         // Copy the Mode page into the databuffer.
04703         //
04704 
04705         RtlCopyMemory(srb->DataBuffer, &cdData->Header, length);
04706 
04707         //
04708         // Set the density code.
04709         //
04710 
04711         ((PERROR_RECOVERY_DATA)srb->DataBuffer)->BlockDescriptor.DensityCode = 0x83;
04712 
04713         IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp);
04714     }
04715 }
04716 
04717 
04718 BOOLEAN
04719 CdRomIsPlayActive(
04720     IN PDEVICE_OBJECT DeviceObject
04721     )
04722 
04723 /*++
04724 
04725 Routine Description:
04726 
04727     This routine determines if the cd is currently playing music.
04728 
04729 Arguments:
04730 
04731     DeviceObject - Device object to test.
04732 
04733 Return Value:
04734 
04735     TRUE if the device is playing music.
04736 
04737 --*/
04738 {
04739     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
04740     IO_STATUS_BLOCK ioStatus;
04741     PSUB_Q_CURRENT_POSITION currentBuffer;
04742 
04743     PAGED_CODE();
04744 
04745     //
04746     // if we don't think it is playing audio, don't bother checking.
04747     //
04748 
04749     if (!PLAY_ACTIVE(fdoExtension)) {
04750         return(FALSE);
04751     }
04752 
04753     currentBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
04754                                           sizeof(SUB_Q_CURRENT_POSITION),
04755                                           CDROM_TAG_PLAY_ACTIVE);
04756 
04757     if (currentBuffer == NULL) {
04758         return(FALSE);
04759     }
04760 
04761     ((PCDROM_SUB_Q_DATA_FORMAT) currentBuffer)->Format = IOCTL_CDROM_CURRENT_POSITION;
04762     ((PCDROM_SUB_Q_DATA_FORMAT) currentBuffer)->Track = 0;
04763 
04764     //
04765     // Build the synchronous request to be sent to ourself
04766     // to perform the request.
04767     //
04768 
04769     ClassSendDeviceIoControlSynchronous(
04770         IOCTL_CDROM_READ_Q_CHANNEL,
04771         DeviceObject,
04772         currentBuffer,
04773         sizeof(CDROM_SUB_Q_DATA_FORMAT),
04774         sizeof(SUB_Q_CURRENT_POSITION),
04775         FALSE,
04776         &ioStatus);
04777 
04778     if (!NT_SUCCESS(ioStatus.Status)) {
04779         ExFreePool(currentBuffer);
04780         return FALSE;
04781     }
04782 
04783     //
04784     // should update the playactive flag here.
04785     //
04786 
04787     if (currentBuffer->Header.AudioStatus == AUDIO_STATUS_IN_PROGRESS) {
04788         PLAY_ACTIVE(fdoExtension) = TRUE;
04789     } else {
04790         PLAY_ACTIVE(fdoExtension) = FALSE;
04791     }
04792 
04793     ExFreePool(currentBuffer);
04794 
04795     return(PLAY_ACTIVE(fdoExtension));
04796 
04797 }
04798 
04799 
04800 VOID
04801 CdRomTickHandler(
04802     IN PDEVICE_OBJECT DeviceObject
04803     )
04804 
04805 /*++
04806 
04807 Routine Description:
04808 
04809     This routine handles the once per second timer provided by the
04810     Io subsystem.  It is used to do delayed retries for cdroms.
04811 
04812 Arguments:
04813 
04814     DeviceObject - what to check.
04815 
04816 Return Value:
04817 
04818     None.
04819 
04820 --*/
04821 
04822 {
04823     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
04824     PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
04825 
04826     ULONG isRemoved;
04827 
04828     KIRQL             oldIrql;
04829 
04830     PIRP              irp;
04831     PIRP              heldIrpList;
04832     PIRP              nextIrp;
04833     PLIST_ENTRY       listEntry;
04834     PCDROM_DATA       cddata;
04835     PIO_STACK_LOCATION irpStack;
04836     UCHAR             uniqueAddress;
04837 
04838     isRemoved = ClassAcquireRemoveLock(DeviceObject, (PIRP) &uniqueAddress);
04839 
04840     //
04841     // We stop the timer before deleting the device.  It's safe to keep going
04842     // if the flag value is REMOVE_PENDING because the removal thread will be
04843     // blocked trying to stop the timer.
04844     //
04845 
04846     ASSERT(isRemoved != REMOVE_COMPLETE);
04847 
04848     //
04849     // This routine is reasonably safe even if the device object has a pending
04850     // remove
04851 
04852     cddata = commonExtension->DriverData;
04853 
04854     //
04855     // Since cdrom is completely synchronized there can never be more than one
04856     // irp delayed for retry at any time.
04857     //
04858 
04859     KeAcquireSpinLock(&(cddata->DelayedRetrySpinLock), &oldIrql);
04860 
04861     if(cddata->DelayedRetryIrp != NULL) {
04862 
04863         PIRP irp = cddata->DelayedRetryIrp;
04864 
04865         //
04866         // If we've got a delayed retry at this point then there had beter
04867         // be an interval for it.
04868         //
04869 
04870         ASSERT(cddata->DelayedRetryInterval != 0);
04871         cddata->DelayedRetryInterval--;
04872 
04873         if(isRemoved) {
04874 
04875             //
04876             // This device is removed - flush the timer queue
04877             //
04878 
04879             cddata->DelayedRetryIrp = NULL;
04880             cddata->DelayedRetryInterval = 0;
04881 
04882             KeReleaseSpinLock(&(cddata->DelayedRetrySpinLock), oldIrql);
04883 
04884             ClassReleaseRemoveLock(DeviceObject, irp);
04885             ClassCompleteRequest(DeviceObject, irp, IO_CD_ROM_INCREMENT);
04886 
04887         } else if (cddata->DelayedRetryInterval == 0) {
04888 
04889             //
04890             // Submit this IRP to the lower driver.  This IRP does not
04891             // need to be remembered here.  It will be handled again when
04892             // it completes.
04893             //
04894 
04895             cddata->DelayedRetryIrp = NULL;
04896 
04897             KeReleaseSpinLock(&(cddata->DelayedRetrySpinLock), oldIrql);
04898 
04899             TraceLog((CdromDebugWarning,
04900                         "CdRomTickHandler: Reissuing request %p (thread = %p)\n",
04901                         irp,
04902                         irp->Tail.Overlay.Thread));
04903 
04904             //
04905             // feed this to the appropriate port driver
04906             //
04907 
04908             CdRomRerunRequest(fdoExtension, irp, cddata->DelayedRetryResend);
04909         } else {
04910             KeReleaseSpinLock(&(cddata->DelayedRetrySpinLock), oldIrql);
04911         }
04912     } else {
04913         KeReleaseSpinLock(&(cddata->DelayedRetrySpinLock), oldIrql);
04914     }
04915 
04916     ClassReleaseRemoveLock(DeviceObject, (PIRP) &uniqueAddress);
04917 }
04918 
04919 
04920 NTSTATUS
04921 CdRomUpdateGeometryCompletion(
04922     PDEVICE_OBJECT DeviceObject,
04923     PIRP Irp,
04924     PVOID Context
04925     )
04926 
04927 /*++
04928 
04929 Routine Description:
04930 
04931     This routine andles the completion of the test unit ready irps
04932     used to determine if the media has changed.  If the media has
04933     changed, this code signals the named event to wake up other
04934     system services that react to media change (aka AutoPlay).
04935 
04936 Arguments:
04937 
04938     DeviceObject - the object for the completion
04939     Irp - the IRP being completed
04940     Context - the SRB from the IRP
04941 
04942 Return Value:
04943 
04944     NTSTATUS
04945 
04946 --*/
04947 
04948 {
04949     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
04950     PCOMMON_DEVICE_EXTENSION commonExtension;
04951 
04952     PSCSI_REQUEST_BLOCK srb = (PSCSI_REQUEST_BLOCK) Context;
04953     PREAD_CAPACITY_DATA readCapacityBuffer;
04954     PIO_STACK_LOCATION  irpStack;
04955     NTSTATUS            status;
04956     BOOLEAN             retry;
04957     ULONG               retryCount;
04958     ULONG               lastSector;
04959     PIRP                originalIrp;
04960     PCDROM_DATA         cddata;
04961     UCHAR               uniqueAddress;
04962 
04963     //
04964     // Get items saved in the private IRP stack location.
04965     //
04966 
04967     irpStack = IoGetCurrentIrpStackLocation(Irp);
04968     retryCount = (ULONG)(ULONG_PTR) irpStack->Parameters.Others.Argument1;
04969     originalIrp = (PIRP) irpStack->Parameters.Others.Argument2;
04970 
04971     if (!DeviceObject) {
04972         DeviceObject = irpStack->DeviceObject;
04973     }
04974     ASSERT(DeviceObject);
04975 
04976     fdoExtension = DeviceObject->DeviceExtension;
04977     commonExtension = DeviceObject->DeviceExtension;
04978     cddata = commonExtension->DriverData;
04979     readCapacityBuffer = srb->DataBuffer;
04980 
04981     if ((NT_SUCCESS(Irp->IoStatus.Status)) && (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_SUCCESS)) {
04982 
04983         CdRomInterpretReadCapacity(DeviceObject, readCapacityBuffer);
04984 
04985     } else {
04986 
04987         ULONG retryInterval;
04988 
04989         TraceLog((CdromDebugWarning,
04990                     "CdRomUpdateGeometryCompletion: [%p] unsuccessful "
04991                     "completion of buddy-irp %p (status - %lx)\n",
04992                     originalIrp, Irp, Irp->IoStatus.Status));
04993 
04994         if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
04995             ClassReleaseQueue(DeviceObject);
04996         }
04997 
04998         retry = ClassInterpretSenseInfo(DeviceObject,
04999                                         srb,
05000                                         IRP_MJ_SCSI,
05001                                         0,
05002                                         retryCount,
05003                                         &status,
05004                                         &retryInterval);
05005         if (retry) {
05006             retryCount--;
05007             if ((retryCount) && (commonExtension->IsRemoved == NO_REMOVE)) {
05008                 PCDB cdb;
05009 
05010                 TraceLog((CdromDebugWarning,
05011                             "CdRomUpdateGeometryCompletion: [%p] Retrying "
05012                             "request %p .. thread is %p\n",
05013                             originalIrp, Irp, Irp->Tail.Overlay.Thread));
05014 
05015                 //
05016                 // set up a one shot timer to get this process started over
05017                 //
05018 
05019                 irpStack->Parameters.Others.Argument1 = ULongToPtr( retryCount );
05020                 irpStack->Parameters.Others.Argument2 = (PVOID) originalIrp;
05021                 irpStack->Parameters.Others.Argument3 = (PVOID) 2;
05022 
05023                 //
05024                 // Setup the IRP to be submitted again in the timer routine.
05025                 //
05026 
05027                 irpStack = IoGetNextIrpStackLocation(Irp);
05028                 irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
05029                 irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
05030                 irpStack->Parameters.Scsi.Srb = srb;
05031                 IoSetCompletionRoutine(Irp,
05032                                        CdRomUpdateGeometryCompletion,
05033                                        srb,
05034                                        TRUE,
05035                                        TRUE,
05036                                        TRUE);
05037 
05038                 //
05039                 // Set up the SRB for read capacity.
05040                 //
05041 
05042                 srb->CdbLength = 10;
05043                 srb->TimeOutValue = fdoExtension->TimeOutValue;
05044                 srb->SrbStatus = srb->ScsiStatus = 0;
05045                 srb->NextSrb = 0;
05046                 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
05047                 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
05048                 srb->SrbFlags = fdoExtension->SrbFlags;
05049                 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
05050                 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
05051                 srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
05052 
05053                 //
05054                 // Set up the CDB
05055                 //
05056 
05057                 cdb = (PCDB) &srb->Cdb[0];
05058                 cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
05059 
05060                 //
05061                 // Requests queued onto this list will be sent to the
05062                 // lower level driver during CdRomTickHandler
05063                 //
05064 
05065                 CdRomRetryRequest(fdoExtension, Irp, retryInterval, TRUE);
05066 
05067                 return STATUS_MORE_PROCESSING_REQUIRED;
05068             }
05069 
05070             if (commonExtension->IsRemoved != NO_REMOVE) {
05071 
05072                 //
05073                 // We cannot retry the request.  Fail it.
05074                 //
05075 
05076                 originalIrp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
05077 
05078             } else {
05079 
05080                 //
05081                 // This has been bounced for a number of times.  Error the
05082                 // original request.
05083                 //
05084 
05085                 originalIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
05086                 RtlZeroMemory(&(fdoExtension->DiskGeometry),
05087                               sizeof(DISK_GEOMETRY));
05088                 fdoExtension->DiskGeometry.BytesPerSector = 2048;
05089                 fdoExtension->SectorShift = 11;
05090                 commonExtension->PartitionLength.QuadPart =
05091                     (LONGLONG)(0x7fffffff);
05092                 fdoExtension->DiskGeometry.MediaType = RemovableMedia;
05093             }
05094         } else {
05095 
05096             //
05097             // Set up reasonable defaults
05098             //
05099 
05100             RtlZeroMemory(&(fdoExtension->DiskGeometry),
05101                           sizeof(DISK_GEOMETRY));
05102             fdoExtension->DiskGeometry.BytesPerSector = 2048;
05103             fdoExtension->SectorShift = 11;
05104             commonExtension->PartitionLength.QuadPart = (LONGLONG)(0x7fffffff);
05105             fdoExtension->DiskGeometry.MediaType = RemovableMedia;
05106         }
05107     }
05108 
05109     //
05110     // Free resources held.
05111     //
05112 
05113     ExFreePool(srb->SenseInfoBuffer);
05114     ExFreePool(srb->DataBuffer);
05115     ExFreePool(srb);
05116     if (Irp->MdlAddress) {
05117         IoFreeMdl(Irp->MdlAddress);
05118     }
05119     IoFreeIrp(Irp);
05120     Irp = NULL;
05121 
05122     if (originalIrp->Tail.Overlay.Thread) {
05123 
05124         TraceLog((CdromDebugTrace,
05125                     "CdRomUpdateGeometryCompletion: [%p] completing "
05126                     "original IRP\n", originalIrp));
05127 
05128     } else {
05129 
05130         KdPrintEx((DPFLTR_CDROM_ID, CdromDebugError,
05131                    "CdRomUpdateGeometryCompletion: completing irp %p which has "
05132                    "no thread\n", originalIrp));
05133 
05134     }
05135     
05136     {
05137         // NOTE: should the original irp be sent down to the device object?
05138         //       it probably should if the SL_OVERRIDER_VERIFY_VOLUME flag
05139         //       is set!
05140         KIRQL oldIrql;
05141         PIO_STACK_LOCATION realIrpStack;
05142 
05143         realIrpStack = IoGetCurrentIrpStackLocation(originalIrp);
05144         oldIrql = KeRaiseIrqlToDpcLevel();
05145 
05146         if (TEST_FLAG(realIrpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME)) {
05147             CdRomStartIo(DeviceObject, originalIrp);
05148         } else {
05149             originalIrp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
05150             originalIrp->IoStatus.Information = 0;
05151             CdRomCompleteIrpAndStartNextPacketSafely(DeviceObject, originalIrp);
05152         }
05153         KeLowerIrql(oldIrql);
05154     }
05155 
05156     return STATUS_MORE_PROCESSING_REQUIRED;
05157 }
05158 
05159 
05160 NTSTATUS
05161 CdRomUpdateCapacity(
05162     IN PFUNCTIONAL_DEVICE_EXTENSION DeviceExtension,
05163     IN PIRP IrpToComplete,
05164     IN OPTIONAL PKEVENT IoctlEvent
05165     )
05166 
05167 /*++
05168 
05169 Routine Description:
05170 
05171     This routine updates the capacity of the disk as recorded in the device extension.
05172     It also completes the IRP given with STATUS_VERIFY_REQUIRED.  This routine is called
05173     when a media change has occurred and it is necessary to determine the capacity of the
05174     new media prior to the next access.
05175 
05176 Arguments:
05177 
05178     DeviceExtension - the device to update
05179     IrpToComplete - the request that needs to be completed when done.
05180 
05181 Return Value:
05182 
05183     NTSTATUS
05184 
05185 --*/
05186 
05187 {
05188     PCOMMON_DEVICE_EXTENSION commonExtension = (PCOMMON_DEVICE_EXTENSION) DeviceExtension;
05189     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION) DeviceExtension;
05190 
05191     PCDB                cdb;
05192     PIRP                irp;
05193     PSCSI_REQUEST_BLOCK srb;
05194     PREAD_CAPACITY_DATA capacityBuffer;
05195     PIO_STACK_LOCATION  irpStack;
05196     PUCHAR              senseBuffer;
05197     NTSTATUS            status;
05198 
05199     irp = IoAllocateIrp((CCHAR)(commonExtension->DeviceObject->StackSize+1),
05200                         FALSE);
05201 
05202     if (irp) {
05203 
05204         srb = ExAllocatePoolWithTag(NonPagedPool,
05205                                     sizeof(SCSI_REQUEST_BLOCK),
05206                                     CDROM_TAG_UPDATE_CAP);
05207         if (srb) {
05208             capacityBuffer = ExAllocatePoolWithTag(
05209                                 NonPagedPoolCacheAligned,
05210                                 sizeof(READ_CAPACITY_DATA),
05211                                 CDROM_TAG_UPDATE_CAP);
05212 
05213             if (capacityBuffer) {
05214 
05215 
05216                 senseBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
05217                                                     SENSE_BUFFER_SIZE,
05218                                                     CDROM_TAG_UPDATE_CAP);
05219 
05220                 if (senseBuffer) {
05221 
05222                     irp->MdlAddress = IoAllocateMdl(capacityBuffer,
05223                                                     sizeof(READ_CAPACITY_DATA),
05224                                                     FALSE,
05225                                                     FALSE,
05226                                                     (PIRP) NULL);
05227 
05228                     if (irp->MdlAddress) {
05229 
05230                         //
05231                         // Have all resources.  Set up the IRP to send for the capacity.
05232                         //
05233 
05234                         IoSetNextIrpStackLocation(irp);
05235                         irp->IoStatus.Status = STATUS_SUCCESS;
05236                         irp->IoStatus.Information = 0;
05237                         irp->Flags = 0;
05238                         irp->UserBuffer = NULL;
05239 
05240                         //
05241                         // Save the device object and retry count in a private stack location.
05242                         //
05243 
05244                         irpStack = IoGetCurrentIrpStackLocation(irp);
05245                         irpStack->DeviceObject = commonExtension->DeviceObject;
05246                         irpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
05247                         irpStack->Parameters.Others.Argument2 = (PVOID) IrpToComplete;
05248 
05249                         //
05250                         // Construct the IRP stack for the lower level driver.
05251                         //
05252 
05253                         irpStack = IoGetNextIrpStackLocation(irp);
05254                         irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
05255                         irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
05256                         irpStack->Parameters.Scsi.Srb = srb;
05257                         IoSetCompletionRoutine(irp,
05258                                                CdRomUpdateGeometryCompletion,
05259                                                srb,
05260                                                TRUE,
05261                                                TRUE,
05262                                                TRUE);
05263                         //
05264                         // Prepare the MDL
05265                         //
05266 
05267                         MmBuildMdlForNonPagedPool(irp->MdlAddress);
05268 
05269 
05270                         //
05271                         // Set up the SRB for read capacity.
05272                         //
05273 
05274                         RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
05275                         RtlZeroMemory(senseBuffer, SENSE_BUFFER_SIZE);
05276                         srb->CdbLength = 10;
05277                         srb->TimeOutValue = DeviceExtension->TimeOutValue;
05278                         srb->SrbStatus = srb->ScsiStatus = 0;
05279                         srb->NextSrb = 0;
05280                         srb->Length = SCSI_REQUEST_BLOCK_SIZE;
05281                         srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
05282                         srb->SrbFlags = DeviceExtension->SrbFlags;
05283                         SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
05284                         SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
05285                         srb->DataBuffer = capacityBuffer;
05286                         srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
05287                         srb->OriginalRequest = irp;
05288                         srb->SenseInfoBuffer = senseBuffer;
05289                         srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
05290 
05291                         //
05292                         // Set up the CDB
05293                         //
05294 
05295                         cdb = (PCDB) &srb->Cdb[0];
05296                         cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
05297 
05298                         //
05299                         // Set the return value in the IRP that will be completed
05300                         // upon completion of the read capacity.
05301                         //
05302 
05303                         IrpToComplete->IoStatus.Status = STATUS_IO_DEVICE_ERROR;
05304                         IoMarkIrpPending(IrpToComplete);
05305 
05306                         IoCallDriver(commonExtension->LowerDeviceObject, irp);
05307 
05308                         //
05309                         // status is not checked because the completion routine for this
05310                         // IRP will always get called and it will free the resources.
05311                         //
05312 
05313                         return STATUS_PENDING;
05314 
05315                     } else {
05316                         ExFreePool(senseBuffer);
05317                         ExFreePool(capacityBuffer);
05318                         ExFreePool(srb);
05319                         IoFreeIrp(irp);
05320                     }
05321                 } else {
05322                     ExFreePool(capacityBuffer);
05323                     ExFreePool(srb);
05324                     IoFreeIrp(irp);
05325                 }
05326             } else {
05327                 ExFreePool(srb);
05328                 IoFreeIrp(irp);
05329             }
05330         } else {
05331             IoFreeIrp(irp);
05332         }
05333     }
05334 
05335     //
05336     // complete the original irp with a failure.
05337     // ISSUE-2000/07/05-henrygab - find a way to avoid failure.
05338     //
05339 
05340     RtlZeroMemory(&(fdoExtension->DiskGeometry),
05341                   sizeof(DISK_GEOMETRY));
05342     fdoExtension->DiskGeometry.BytesPerSector = 2048;
05343     fdoExtension->SectorShift = 11;
05344     commonExtension->PartitionLength.QuadPart =
05345         (LONGLONG)(0x7fffffff);
05346     fdoExtension->DiskGeometry.MediaType = RemovableMedia;
05347 
05348     IrpToComplete->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
05349     IrpToComplete->IoStatus.Information = 0;
05350 
05351     BAIL_OUT(IrpToComplete);
05352     CdRomCompleteIrpAndStartNextPacketSafely(commonExtension->DeviceObject,
05353                                              IrpToComplete);
05354     return STATUS_INSUFFICIENT_RESOURCES;
05355 }
05356 
05357 
05358 NTSTATUS
05359 CdRomRemoveDevice(
05360     IN PDEVICE_OBJECT DeviceObject,
05361     IN UCHAR Type
05362     )
05363 
05364 /*++
05365 
05366 Routine Description:
05367 
05368     This routine is responsible for releasing any resources in use by the
05369     cdrom driver and shutting down it's timer routine.  This routine is called
05370     when all outstanding requests have been completed and the device has
05371     disappeared - no requests may be issued to the lower drivers.
05372 
05373 Arguments:
05374 
05375     DeviceObject - the device object being removed
05376 
05377 Return Value:
05378 
05379     none - this routine may not fail
05380 
05381 --*/
05382 
05383 {
05384     PFUNCTIONAL_DEVICE_EXTENSION deviceExtension =
05385         DeviceObject->DeviceExtension;
05386 
05387     PCDROM_DATA cdData = deviceExtension->CommonExtension.DriverData;
05388 
05389     PAGED_CODE();
05390 
05391     if((Type == IRP_MN_QUERY_REMOVE_DEVICE) ||
05392        (Type == IRP_MN_CANCEL_REMOVE_DEVICE)) {
05393         return STATUS_SUCCESS;
05394     }
05395 
05396     if(cdData->DelayedRetryIrp != NULL) {
05397         cdData->DelayedRetryInterval = 1;
05398         CdRomTickHandler(DeviceObject);
05399     }
05400 
05401     CdRomDeAllocateMmcResources(DeviceObject);
05402 
05403     if (deviceExtension->DeviceDescriptor) {
05404         ExFreePool(deviceExtension->DeviceDescriptor);
05405         deviceExtension->DeviceDescriptor = NULL;
05406     }
05407 
05408     if (deviceExtension->AdapterDescriptor) {
05409         ExFreePool(deviceExtension->AdapterDescriptor);
05410         deviceExtension->AdapterDescriptor = NULL;
05411     }
05412 
05413     if (deviceExtension->SenseData) {
05414         ExFreePool(deviceExtension->SenseData);
05415         deviceExtension->SenseData = NULL;
05416     }
05417 
05418     ClassDeleteSrbLookasideList(&deviceExtension->CommonExtension);
05419 
05420     if(cdData->CdromInterfaceString.Buffer != NULL) {
05421         IoSetDeviceInterfaceState(
05422             &(cdData->CdromInterfaceString),
05423             FALSE);
05424         RtlFreeUnicodeString(&(cdData->CdromInterfaceString));
05425         RtlInitUnicodeString(&(cdData->CdromInterfaceString), NULL);
05426     }
05427 
05428     if(cdData->VolumeInterfaceString.Buffer != NULL) {
05429         IoSetDeviceInterfaceState(
05430             &(cdData->VolumeInterfaceString),
05431             FALSE);
05432         RtlFreeUnicodeString(&(cdData->VolumeInterfaceString));
05433         RtlInitUnicodeString(&(cdData->VolumeInterfaceString), NULL);
05434     }
05435 
05436     CdRomDeleteWellKnownName(DeviceObject);
05437 
05438     ASSERT(cdData->DelayedRetryIrp == NULL);
05439 
05440     if(Type == IRP_MN_REMOVE_DEVICE) {
05441 
05442         if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_LOCKED_PAGES)) {
05443             
05444             //
05445             // unlock locked pages by locking (to get Mm pointer)
05446             // and then unlocking twice.
05447             //
05448             
05449             PVOID locked;
05450 
05451             if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_HITACHI_1750)) {
05452                 
05453                 locked = MmLockPagableCodeSection(HitachiProcessError);
05454 
05455             } else if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_HITACHI_GD_2000)) {
05456 
05457                 locked = MmLockPagableCodeSection(HitachiProcessErrorGD2000);
05458 
05459             } else if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_TOSHIBA_XM_3xx )) {
05460             
05461                 locked = MmLockPagableCodeSection(ToshibaProcessError);
05462             
05463             } else {
05464 
05465                 // this is a problem!
05466                 // workaround by locking this twice, once for us and
05467                 // once for the non-existant locker from ScanForSpecial
05468                 ASSERT(!"hack flags show locked section, but none exists?");
05469                 locked = MmLockPagableCodeSection(CdRomRemoveDevice);
05470                 locked = MmLockPagableCodeSection(CdRomRemoveDevice);
05471 
05472 
05473             }
05474 
05475             MmUnlockPagableImageSection(locked);
05476             MmUnlockPagableImageSection(locked);
05477 
05478         }
05479 
05480         //
05481         // keep the system-wide count accurate, as
05482         // programs use this info to know when they 
05483         // have found all the cdroms in a system.
05484         //
05485 
05486         TraceLog((CdromDebugTrace,
05487                     "CDROM.SYS Remove device\n"));
05488         IoGetConfigurationInformation()->CdRomCount--;
05489     }
05490 
05491     //
05492     // so long, and thanks for all the fish!
05493     //
05494 
05495     return STATUS_SUCCESS;
05496 }
05497 
05498 
05499 DEVICE_TYPE
05500 CdRomGetDeviceType(
05501     IN PDEVICE_OBJECT DeviceObject
05502     )
05503 /*++
05504 
05505 Routine Description:
05506 
05507     This routine figures out the real device type
05508     by checking CDVD_CAPABILITIES_PAGE
05509 
05510 Arguments:
05511 
05512     DeviceObject -
05513 
05514 Return Value:
05515 
05516     FILE_DEVICE_CD_ROM or FILE_DEVICE_DVD
05517 
05518 
05519 --*/
05520 {
05521     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
05522     PCDROM_DATA cdromExtension;
05523     ULONG bufLength;
05524     SCSI_REQUEST_BLOCK srb;
05525     PCDB cdb;
05526     PMODE_PARAMETER_HEADER10 modePageHeader;
05527     PCDVD_CAPABILITIES_PAGE capPage;
05528     ULONG capPageOffset;
05529     DEVICE_TYPE deviceType;
05530     NTSTATUS status;
05531     BOOLEAN use6Byte;
05532 
05533     PAGED_CODE();
05534 
05535     //
05536     // NOTE: don't cache this until understand how it affects GetMediaTypes()
05537     //
05538 
05539     //
05540     // default device type
05541     //
05542 
05543     deviceType = FILE_DEVICE_CD_ROM;
05544 
05545     fdoExtension = DeviceObject->DeviceExtension;
05546 
05547     cdromExtension = fdoExtension->CommonExtension.DriverData;
05548 
05549     use6Byte = TEST_FLAG(cdromExtension->XAFlags, XA_USE_6_BYTE);
05550 
05551     RtlZeroMemory(&srb, sizeof(srb));
05552     cdb = (PCDB)srb.Cdb;
05553 
05554     //
05555     // Build the MODE SENSE CDB. The data returned will be kept in the
05556     // device extension and used to set block size.
05557     //
05558     if (use6Byte) {
05559 
05560         bufLength = sizeof(CDVD_CAPABILITIES_PAGE) +
05561                     sizeof(MODE_PARAMETER_HEADER);
05562 
05563         capPageOffset = sizeof(MODE_PARAMETER_HEADER);
05564 
05565         cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
05566         cdb->MODE_SENSE.Dbd = 1;
05567         cdb->MODE_SENSE.PageCode = MODE_PAGE_CAPABILITIES;
05568         cdb->MODE_SENSE.AllocationLength = (UCHAR)bufLength;
05569         srb.CdbLength = 6;
05570     } else {
05571 
05572         bufLength = sizeof(CDVD_CAPABILITIES_PAGE) +
05573                     sizeof(MODE_PARAMETER_HEADER10);
05574 
05575         capPageOffset = sizeof(MODE_PARAMETER_HEADER10);
05576 
05577         cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
05578         cdb->MODE_SENSE10.Dbd = 1;
05579         cdb->MODE_SENSE10.PageCode = MODE_PAGE_CAPABILITIES;
05580         cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(bufLength >> 8);
05581         cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(bufLength >> 0);
05582         srb.CdbLength = 10;
05583     }
05584 
05585     //
05586     // Set timeout value from device extension.
05587     //
05588     srb.TimeOutValue = fdoExtension->TimeOutValue;
05589 
05590     modePageHeader = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
05591                                            bufLength,
05592                                            CDROM_TAG_MODE_DATA);
05593     if (modePageHeader) {
05594 
05595         RtlZeroMemory(modePageHeader, bufLength);
05596 
05597         status = ClassSendSrbSynchronous(
05598                      DeviceObject,
05599                      &srb,
05600                      modePageHeader,
05601                      bufLength,
05602                      FALSE);
05603 
05604         if (NT_SUCCESS(status) ||
05605             (status == STATUS_DATA_OVERRUN) ||
05606             (status == STATUS_BUFFER_OVERFLOW)
05607             ) {
05608 
05609             capPage = (PCDVD_CAPABILITIES_PAGE) (((PUCHAR) modePageHeader) + capPageOffset);
05610 
05611             if ((capPage->PageCode == MODE_PAGE_CAPABILITIES) &&
05612                 (capPage->DVDROMRead || capPage->DVDRRead ||
05613                  capPage->DVDRAMRead || capPage->DVDRWrite ||
05614                  capPage->DVDRAMWrite)) {
05615 
05616                 deviceType = FILE_DEVICE_DVD;
05617             }
05618         }
05619         ExFreePool (modePageHeader);
05620     }
05621 
05622     return deviceType;
05623 }
05624 
05625 
05626 NTSTATUS
05627 CdRomCreateWellKnownName(
05628     IN PDEVICE_OBJECT DeviceObject
05629     )
05630 /*++
05631 
05632 Routine Description:
05633 
05634     This routine creates a symbolic link to the cdrom device object
05635     under \dosdevices.  The number of the cdrom device does not neccessarily
05636     match between \dosdevices and \device, but usually will be the same.
05637 
05638     Saves the buffer
05639 
05640 Arguments:
05641 
05642     DeviceObject -
05643 
05644 Return Value:
05645 
05646     NTSTATUS
05647 
05648 --*/
05649 {
05650     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
05651     PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
05652     PCDROM_DATA cdromData = commonExtension->DriverData;
05653 
05654     UNICODE_STRING unicodeLinkName;
05655     WCHAR wideLinkName[64];
05656     PWCHAR savedName;
05657 
05658     LONG cdromNumber = fdoExtension->DeviceNumber;
05659 
05660     NTSTATUS status;
05661 
05662     //
05663     // if already linked, assert then return
05664     //
05665 
05666     if (cdromData->WellKnownName.Buffer != NULL) {
05667 
05668         TraceLog((CdromDebugError,
05669                     "CdRomCreateWellKnownName: link already exists %p\n",
05670                     cdromData->WellKnownName.Buffer));
05671         ASSERT(FALSE);
05672         return STATUS_UNSUCCESSFUL;
05673 
05674     }
05675 
05676     //
05677     // find an unused CdRomNN to link to
05678     //
05679 
05680     do {
05681 
05682         swprintf(wideLinkName, L"\\DosDevices\\CdRom%d", cdromNumber);
05683         RtlInitUnicodeString(&unicodeLinkName, wideLinkName);
05684         status = IoCreateSymbolicLink(&unicodeLinkName,
05685                                       &(commonExtension->DeviceName));
05686 
05687         cdromNumber++;
05688 
05689     } while((status == STATUS_OBJECT_NAME_COLLISION) ||
05690             (status == STATUS_OBJECT_NAME_EXISTS));
05691 
05692     if (!NT_SUCCESS(status)) {
05693 
05694         TraceLog((CdromDebugWarning,
05695                     "CdRomCreateWellKnownName: Error %lx linking %wZ to "
05696                     "device %wZ\n",
05697                     status,
05698                     &unicodeLinkName,
05699                     &(commonExtension->DeviceName)));
05700         return status;
05701 
05702     }
05703 
05704     TraceLog((CdromDebugWarning,
05705                 "CdRomCreateWellKnownName: successfully linked %wZ "
05706                 "to device %wZ\n",
05707                 &unicodeLinkName,
05708                 &(commonExtension->DeviceName)));
05709 
05710     //
05711     // Save away the symbolic link name in the driver data block.  We need
05712     // it so we can delete the link when the device is removed.
05713     //
05714 
05715     savedName = ExAllocatePoolWithTag(PagedPool,
05716                                       unicodeLinkName.MaximumLength,
05717                                       CDROM_TAG_STRINGS);
05718 
05719     if (savedName == NULL) {
05720         IoDeleteSymbolicLink(&unicodeLinkName);
05721         return STATUS_INSUFFICIENT_RESOURCES;
05722     }
05723 
05724     RtlCopyMemory(savedName,
05725                   unicodeLinkName.Buffer,
05726                   unicodeLinkName.MaximumLength);
05727 
05728     RtlInitUnicodeString(&(cdromData->WellKnownName), savedName);
05729 
05730     //
05731     // the name was saved and the link created
05732     //
05733 
05734     return STATUS_SUCCESS;
05735 }
05736 
05737 
05738 VOID
05739 CdRomDeleteWellKnownName(
05740     IN PDEVICE_OBJECT DeviceObject
05741     )
05742 {
05743     PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
05744     PCDROM_DATA cdromData = commonExtension->DriverData;
05745 
05746     if(cdromData->WellKnownName.Buffer != NULL) {
05747 
05748         IoDeleteSymbolicLink(&(cdromData->WellKnownName));
05749         ExFreePool(cdromData->WellKnownName.Buffer);
05750         cdromData->WellKnownName.Buffer = NULL;
05751         cdromData->WellKnownName.Length = 0;
05752         cdromData->WellKnownName.MaximumLength = 0;
05753 
05754     }
05755     return;
05756 }
05757 
05758 
05759 NTSTATUS
05760 CdRomGetDeviceParameter (
05761     IN     PDEVICE_OBJECT      Fdo,
05762     IN     PWSTR               ParameterName,
05763     IN OUT PULONG              ParameterValue
05764     )
05765 /*++
05766 
05767 Routine Description:
05768 
05769     retrieve a devnode registry parameter
05770 
05771 Arguments:
05772 
05773     DeviceObject - Cdrom Device Object
05774 
05775     ParameterName - parameter name to look up
05776 
05777     ParameterValuse - default parameter value
05778 
05779 Return Value:
05780 
05781     NT Status
05782 
05783 --*/
05784 {
05785     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
05786     NTSTATUS                 status;
05787     HANDLE                   deviceParameterHandle;
05788     RTL_QUERY_REGISTRY_TABLE queryTable[2];
05789     ULONG                    defaultParameterValue;
05790 
05791     PAGED_CODE();
05792 
05793     //
05794     // open the given parameter
05795     //
05796     status = IoOpenDeviceRegistryKey(fdoExtension->LowerPdo,
05797                                      PLUGPLAY_REGKEY_DRIVER,
05798                                      KEY_READ,
05799                                      &deviceParameterHandle);
05800 
05801     if(NT_SUCCESS(status)) {
05802 
05803         RtlZeroMemory(queryTable, sizeof(queryTable));
05804 
05805         defaultParameterValue = *ParameterValue;
05806 
05807         queryTable->Flags         = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
05808         queryTable->Name          = ParameterName;
05809         queryTable->EntryContext  = ParameterValue;
05810         queryTable->DefaultType   = REG_NONE;
05811         queryTable->DefaultData   = NULL;
05812         queryTable->DefaultLength = 0;
05813 
05814         status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
05815                                         (PWSTR) deviceParameterHandle,
05816                                         queryTable,
05817                                         NULL,
05818                                         NULL);
05819         if (!NT_SUCCESS(status)) {
05820 
05821             *ParameterValue = defaultParameterValue;
05822         }
05823 
05824         //
05825         // close what we open
05826         //
05827         ZwClose(deviceParameterHandle);
05828     }
05829 
05830     return status;
05831 
05832 } // CdRomGetDeviceParameter
05833 
05834 
05835 NTSTATUS
05836 CdRomSetDeviceParameter (
05837     IN PDEVICE_OBJECT Fdo,
05838     IN PWSTR          ParameterName,
05839     IN ULONG          ParameterValue
05840     )
05841 /*++
05842 
05843 Routine Description:
05844 
05845     save a devnode registry parameter
05846 
05847 Arguments:
05848 
05849     DeviceObject - Cdrom Device Object
05850 
05851     ParameterName - parameter name
05852 
05853     ParameterValuse - parameter value
05854 
05855 Return Value:
05856 
05857     NT Status
05858 
05859 --*/
05860 {
05861     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
05862     NTSTATUS                 status;
05863     HANDLE                   deviceParameterHandle;
05864 
05865     PAGED_CODE();
05866 
05867     //
05868     // open the given parameter
05869     //
05870     status = IoOpenDeviceRegistryKey(fdoExtension->LowerPdo,
05871                                      PLUGPLAY_REGKEY_DRIVER,
05872                                      KEY_READ | KEY_WRITE,
05873                                      &deviceParameterHandle);
05874 
05875     if(NT_SUCCESS(status)) {
05876 
05877         status = RtlWriteRegistryValue(
05878                     RTL_REGISTRY_HANDLE,
05879                     (PWSTR) deviceParameterHandle,
05880                     ParameterName,
05881                     REG_DWORD,
05882                     &ParameterValue,
05883                     sizeof (ParameterValue));
05884 
05885         //
05886         // close what we open
05887         //
05888         ZwClose(deviceParameterHandle);
05889     }
05890 
05891     return status;
05892 
05893 } // CdromSetDeviceParameter
05894 
05895 
05896 VOID
05897 CdRomPickDvdRegion(
05898     IN PDEVICE_OBJECT Fdo
05899     )
05900 /*++
05901 
05902 Routine Description:
05903 
05904     pick a default dvd region
05905 
05906 Arguments:
05907 
05908     DeviceObject - Cdrom Device Object
05909 
05910 Return Value:
05911 
05912     NT Status
05913 
05914 --*/
05915 {
05916     PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
05917     PCDROM_DATA cddata = (PCDROM_DATA)(commonExtension->DriverData);
05918 
05919     //
05920     // these five pointers all point to dvdReadStructure or part of
05921     // its data, so don't deallocate them more than once!
05922     //
05923 
05924     PDVD_READ_STRUCTURE dvdReadStructure;
05925     PDVD_COPY_PROTECT_KEY copyProtectKey;
05926     PDVD_COPYRIGHT_DESCRIPTOR dvdCopyRight;
05927     PDVD_RPC_KEY rpcKey;
05928     PDVD_SET_RPC_KEY dvdRpcKey;
05929 
05930     IO_STATUS_BLOCK ioStatus;
05931     ULONG bufferLen;
05932     UCHAR mediaRegion;
05933     ULONG pickDvdRegion;
05934     ULONG defaultDvdRegion;
05935     ULONG dvdRegion;
05936     ULONG a, b;
05937 
05938 
05939     PAGED_CODE();
05940 
05941     if ((pickDvdRegion = InterlockedExchange(&cddata->PickDvdRegion, 0)) == 0) {
05942 
05943         //
05944         // it was non-zero, so either another thread will do this, or
05945         // we no longer need to pick a region
05946         //
05947 
05948         return;
05949     }
05950 
05951     //
05952     // short-circuit if license agreement violated
05953     //
05954 
05955     if (cddata->DvdRpc0LicenseFailure) {
05956         TraceLog((CdromDebugWarning,
05957                     "DVD License failure.  Refusing to pick a region\n"));
05958         InterlockedExchange(&cddata->PickDvdRegion, 0);
05959         return;
05960     }
05961 
05962 
05963 
05964     a = max(sizeof(DVD_DESCRIPTOR_HEADER) +
05965                             sizeof(DVD_COPYRIGHT_DESCRIPTOR),
05966                         sizeof(DVD_READ_STRUCTURE)
05967                         );
05968                         b = max(DVD_RPC_KEY_LENGTH,
05969                         DVD_SET_RPC_KEY_LENGTH
05970                         );
05971     bufferLen = max(a, b);
05972 
05973     dvdReadStructure = (PDVD_READ_STRUCTURE)
05974         ExAllocatePoolWithTag(PagedPool, bufferLen, DVD_TAG_DVD_REGION);
05975 
05976     if (dvdReadStructure == NULL) {
05977         InterlockedExchange(&cddata->PickDvdRegion, pickDvdRegion);
05978         return;
05979     }
05980 
05981     if (cddata->DvdRpc0Device && cddata->Rpc0RetryRegistryCallback) {
05982 
05983         TraceLog((CdromDebugWarning,
05984                     "CdRomPickDvdRegion (%p): now retrying RPC0 callback\n",
05985                     Fdo));
05986 
05987         //
05988         // get the registry settings again
05989         //
05990 
05991         ioStatus.Status = CdRomGetRpc0Settings(Fdo);
05992 
05993         if (ioStatus.Status == STATUS_LICENSE_VIOLATION) {
05994 
05995             //
05996             // if this is the returned error, then
05997             // the routine should have set this!
05998             //
05999 
06000             ASSERT(cddata->DvdRpc0LicenseFailure);
06001             cddata->DvdRpc0LicenseFailure = 1;
06002             TraceLog((CdromDebugWarning,
06003                         "CdRomPickDvdRegion (%p): "
06004                         "setting to fail all dvd ioctls due to CSS licensing "
06005                         "failure.\n", Fdo));
06006 
06007             pickDvdRegion = 0;
06008             goto getout;
06009 
06010         }
06011 
06012         //
06013         // get the device region, again
06014         //
06015 
06016         copyProtectKey = (PDVD_COPY_PROTECT_KEY)dvdReadStructure;
06017         RtlZeroMemory(copyProtectKey, bufferLen);
06018         copyProtectKey->KeyLength = DVD_RPC_KEY_LENGTH;
06019         copyProtectKey->KeyType = DvdGetRpcKey;
06020 
06021         //
06022         // Build a request for READ_KEY
06023         //
06024 
06025         ClassSendDeviceIoControlSynchronous(
06026             IOCTL_DVD_READ_KEY,
06027             Fdo,
06028             copyProtectKey,
06029             DVD_RPC_KEY_LENGTH,
06030             DVD_RPC_KEY_LENGTH,
06031             FALSE,
06032             &ioStatus);
06033 
06034         if (!NT_SUCCESS(ioStatus.Status)) {
06035             TraceLog((CdromDebugWarning,
06036                         "CdRomPickDvdRegion: Unable to get "
06037                         "device RPC data (%x)\n", ioStatus.Status));
06038             pickDvdRegion = 0;
06039             goto getout;
06040         }
06041 
06042         //
06043         // now that we have gotten the device's RPC data,
06044         // we have set the device extension to usable data.
06045         // no need to call back into this section of code again
06046         //
06047 
06048         cddata->Rpc0RetryRegistryCallback = 0;
06049 
06050 
06051         rpcKey = (PDVD_RPC_KEY) copyProtectKey->KeyData;
06052 
06053         //
06054         // TypeCode of zero means that no region has been set.
06055         //
06056 
06057         if (rpcKey->TypeCode != 0) {
06058             TraceLog((CdromDebugWarning,
06059                         "CdRomPickDvdRegion (%p): DVD Region already "
06060                         "chosen\n", Fdo));
06061             pickDvdRegion = 0;
06062             goto getout;
06063         }
06064 
06065         TraceLog((CdromDebugWarning,
06066                     "CdRomPickDvdRegion (%p): must choose initial DVD "
06067                     " Region\n", Fdo));
06068     }
06069 
06070 
06071 
06072     copyProtectKey = (PDVD_COPY_PROTECT_KEY) dvdReadStructure;
06073 
06074     dvdCopyRight = (PDVD_COPYRIGHT_DESCRIPTOR)
06075         ((PDVD_DESCRIPTOR_HEADER) dvdReadStructure)->Data;
06076 
06077     //
06078     // get the media region
06079     //
06080 
06081     RtlZeroMemory (dvdReadStructure, bufferLen);
06082     dvdReadStructure->Format = DvdCopyrightDescriptor;
06083 
06084     //
06085     // Build and send a request for READ_KEY
06086     //
06087 
06088     TraceLog((CdromDebugTrace,
06089                 "CdRomPickDvdRegion (%p): Getting Copyright Descriptor\n",
06090                 Fdo));
06091 
06092     ClassSendDeviceIoControlSynchronous(
06093         IOCTL_DVD_READ_STRUCTURE,
06094         Fdo,
06095         dvdReadStructure,
06096         sizeof(DVD_READ_STRUCTURE),
06097         sizeof (DVD_DESCRIPTOR_HEADER) +
06098         sizeof(DVD_COPYRIGHT_DESCRIPTOR),
06099         FALSE,
06100         &ioStatus
06101         );
06102     TraceLog((CdromDebugTrace,
06103                 "CdRomPickDvdRegion (%p): Got Copyright Descriptor %x\n",
06104                 Fdo, ioStatus.Status));
06105 
06106     if ((NT_SUCCESS(ioStatus.Status)) &&
06107         (dvdCopyRight->CopyrightProtectionType == 0x01)
06108         ) {
06109 
06110         //
06111         // keep the media region bitmap around
06112         // a 1 means ok to play
06113         //
06114 
06115         if (dvdCopyRight->RegionManagementInformation == 0xff) {
06116             TraceLog((CdromDebugError,
06117                       "CdRomPickDvdRegion (%p): RegionManagementInformation "
06118                       "is set to dis-allow playback for all regions.  This is "
06119                       "most likely a poorly authored disc.  defaulting to all "
06120                       "region disc for purpose of choosing initial region\n",
06121                       Fdo));
06122             dvdCopyRight->RegionManagementInformation = 0;
06123         }
06124 
06125 
06126         mediaRegion = ~dvdCopyRight->RegionManagementInformation;
06127 
06128     } else {
06129 
06130         //
06131         // could be media, can't set the device region
06132         //
06133 
06134         if (!cddata->DvdRpc0Device) {
06135 
06136             //
06137             // can't automatically pick a default region on a rpc2 drive
06138             // without media, so just exit
06139             //
06140             TraceLog((CdromDebugWarning,
06141                         "CdRomPickDvdRegion (%p): failed to auto-choose "
06142                         "a region due to status %x getting copyright "
06143                         "descriptor\n", Fdo, ioStatus.Status));
06144             goto getout;
06145 
06146         } else {
06147 
06148             //
06149             // for an RPC0 drive, we can try to pick a region for
06150             // the drive
06151             //
06152 
06153             mediaRegion = 0x0;
06154         }
06155 
06156     }
06157 
06158     //
06159     // get the device region
06160     //
06161 
06162     RtlZeroMemory (copyProtectKey, bufferLen);
06163     copyProtectKey->KeyLength = DVD_RPC_KEY_LENGTH;
06164     copyProtectKey->KeyType = DvdGetRpcKey;
06165 
06166     //
06167     // Build and send a request for READ_KEY for RPC key
06168     //
06169 
06170     TraceLog((CdromDebugTrace,
06171                 "CdRomPickDvdRegion (%p): Getting RpcKey\n",
06172                 Fdo));
06173     ClassSendDeviceIoControlSynchronous(
06174         IOCTL_DVD_READ_KEY,
06175         Fdo,
06176         copyProtectKey,
06177         DVD_RPC_KEY_LENGTH,
06178         DVD_RPC_KEY_LENGTH,
06179         FALSE,
06180         &ioStatus
06181         );
06182     TraceLog((CdromDebugTrace,
06183                 "CdRomPickDvdRegion (%p): Got RpcKey %x\n",
06184                 Fdo, ioStatus.Status));
06185 
06186     if (!NT_SUCCESS(ioStatus.Status)) {
06187 
06188         TraceLog((CdromDebugWarning,
06189                     "CdRomPickDvdRegion (%p): failed to get RpcKey from "
06190                     "a DVD Device\n", Fdo));
06191         goto getout;
06192 
06193     }
06194 
06195     //
06196     // so we now have what we can get for the media region and the
06197     // drive region.  we will not set a region if the drive has one
06198     // set already (mask is not all 1's), nor will we set a region
06199     // if there are no more user resets available.
06200     //
06201 
06202     rpcKey = (PDVD_RPC_KEY) copyProtectKey->KeyData;
06203 
06204 
06205     if (rpcKey->RegionMask != 0xff) {
06206         TraceLog((CdromDebugWarning,
06207                     "CdRomPickDvdRegion (%p): not picking a region since "
06208                     "it is already chosen\n", Fdo));
06209         goto getout;
06210     }
06211 
06212     if (rpcKey->UserResetsAvailable <= 1) {
06213         TraceLog((CdromDebugWarning,
06214                     "CdRomPickDvdRegion (%p): not picking a region since "
06215                     "only one change remains\n", Fdo));
06216         goto getout;
06217     }
06218 
06219     defaultDvdRegion = 0;
06220 
06221     //
06222     // the proppage dvd class installer sets
06223     // this key based upon the system locale
06224     //
06225 
06226     CdRomGetDeviceParameter (
06227         Fdo,
06228         DVD_DEFAULT_REGION,
06229         &defaultDvdRegion
06230         );
06231 
06232     if (defaultDvdRegion > DVD_MAX_REGION) {
06233 
06234         //
06235         // the registry has a bogus default
06236         //
06237 
06238         TraceLog((CdromDebugWarning,
06239                     "CdRomPickDvdRegion (%p): registry has a bogus default "
06240                     "region value of %x\n", Fdo, defaultDvdRegion));
06241         defaultDvdRegion = 0;
06242 
06243     }
06244 
06245     //
06246     // if defaultDvdRegion == 0, it means no default.
06247     //
06248 
06249     //
06250     // we will select the initial dvd region for the user
06251     //
06252 
06253     if ((defaultDvdRegion != 0) &&
06254         (mediaRegion &
06255          (1 << (defaultDvdRegion - 1))
06256          )
06257         ) {
06258 
06259         //
06260         // first choice:
06261         // the media has region that matches
06262         // the default dvd region.
06263         //
06264 
06265         dvdRegion = (1 << (defaultDvdRegion - 1));
06266 
06267         TraceLog((CdromDebugWarning,
06268                     "CdRomPickDvdRegion (%p): Choice #1: media matches "
06269                     "drive's default, chose region %x\n", Fdo, dvdRegion));
06270 
06271 
06272     } else if (mediaRegion) {
06273 
06274         //
06275         // second choice:
06276         // pick the lowest region number
06277         // from the media
06278         //
06279 
06280         UCHAR mask;
06281 
06282         mask = 1;
06283         dvdRegion = 0;
06284         while (mediaRegion && !dvdRegion) {
06285 
06286             //
06287             // pick the lowest bit
06288             //
06289             dvdRegion = mediaRegion & mask;
06290             mask <<= 1;
06291         }
06292 
06293         TraceLog((CdromDebugWarning,
06294                     "CdRomPickDvdRegion (%p): Choice #2: choosing lowest "
06295                     "media region %x\n", Fdo, dvdRegion));
06296 
06297     } else if (defaultDvdRegion) {
06298 
06299         //
06300         // third choice:
06301         // default dvd region from the dvd class installer
06302         //
06303 
06304         dvdRegion = (1 << (defaultDvdRegion - 1));
06305         TraceLog((CdromDebugWarning,
06306                     "CdRomPickDvdRegion (%p): Choice #3: using default "
06307                     "region for this install %x\n", Fdo, dvdRegion));
06308 
06309     } else {
06310 
06311         //
06312         // unable to pick one for the user -- this should rarely
06313         // happen, since the proppage dvd class installer sets
06314         // the key based upon the system locale
06315         //
06316         TraceLog((CdromDebugWarning,
06317                     "CdRomPickDvdRegion (%p): Choice #4: failed to choose "
06318                     "a media region\n", Fdo));
06319         goto getout;
06320 
06321     }
06322 
06323     //
06324     // now that we've chosen a region, set the region by sending the
06325     // appropriate request to the drive
06326     //
06327 
06328     RtlZeroMemory (copyProtectKey, bufferLen);
06329     copyProtectKey->KeyLength = DVD_SET_RPC_KEY_LENGTH;
06330     copyProtectKey->KeyType = DvdSetRpcKey;
06331     dvdRpcKey = (PDVD_SET_RPC_KEY) copyProtectKey->KeyData;
06332     dvdRpcKey->PreferredDriveRegionCode = (UCHAR) ~dvdRegion;
06333 
06334     //
06335     // Build and send request for SEND_KEY
06336     //
06337     TraceLog((CdromDebugTrace,
06338                 "CdRomPickDvdRegion (%p): Sending new Rpc Key to region %x\n",
06339                 Fdo, dvdRegion));
06340 
06341     ClassSendDeviceIoControlSynchronous(
06342         IOCTL_DVD_SEND_KEY2,
06343         Fdo,
06344         copyProtectKey,
06345         DVD_SET_RPC_KEY_LENGTH,
06346         0,
06347         FALSE,
06348         &ioStatus);
06349     TraceLog((CdromDebugTrace,
06350                 "CdRomPickDvdRegion (%p): Sent new Rpc Key %x\n",
06351                 Fdo, ioStatus.Status));
06352 
06353     if (!NT_SUCCESS(ioStatus.Status)) {
06354         DebugPrint ((1, "CdRomPickDvdRegion (%p): unable to set dvd initial "
06355                      " region code (%p)\n", Fdo, ioStatus.Status));
06356     } else {
06357         DebugPrint ((1, "CdRomPickDvdRegion (%p): Successfully set dvd "
06358                      "initial region\n", Fdo));
06359         pickDvdRegion = 0;
06360     }
06361 
06362 getout:
06363     if (dvdReadStructure) {
06364         ExFreePool (dvdReadStructure);
06365     }
06366 
06367     //
06368     // update the new PickDvdRegion value
06369     //
06370 
06371     InterlockedExchange(&cddata->PickDvdRegion, pickDvdRegion);
06372 
06373     return;
06374 }
06375 
06376 
06377 NTSTATUS
06378 CdRomRetryRequest(
06379     IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
06380     IN PIRP Irp,
06381     IN ULONG Delay,
06382     IN BOOLEAN ResendIrp
06383     )
06384 {
06385     PCDROM_DATA cdData;
06386     KIRQL oldIrql;
06387 
06388     if(Delay == 0) {
06389         return CdRomRerunRequest(FdoExtension, Irp, ResendIrp);
06390     }
06391 
06392     cdData = FdoExtension->CommonExtension.DriverData;
06393 
06394     KeAcquireSpinLock(&(cdData->DelayedRetrySpinLock), &oldIrql);
06395 
06396     ASSERT(cdData->DelayedRetryIrp == NULL);
06397     ASSERT(cdData->DelayedRetryInterval == 0);
06398 
06399     cdData->DelayedRetryIrp = Irp;
06400     cdData->DelayedRetryInterval = Delay;
06401     cdData->DelayedRetryResend = ResendIrp;
06402 
06403     KeReleaseSpinLock(&(cdData->DelayedRetrySpinLock), oldIrql);
06404 
06405     return STATUS_PENDING;
06406 }
06407 
06408 
06409 NTSTATUS
06410 CdRomRerunRequest(
06411     IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
06412     IN OPTIONAL PIRP Irp,
06413     IN BOOLEAN ResendIrp
06414     )
06415 {
06416     if(ResendIrp) {
06417         return IoCallDriver(FdoExtension->CommonExtension.LowerDeviceObject,
06418                             Irp);
06419     } else {
06420         KIRQL oldIrql;
06421 
06422         oldIrql = KeRaiseIrqlToDpcLevel();
06423         CdRomStartIo(FdoExtension->DeviceObject, Irp);
06424         KeLowerIrql(oldIrql);
06425         return STATUS_MORE_PROCESSING_REQUIRED;
06426     }
06427 }
06428 
06429 
06430 /*++
06431 
06432 Routine Description:
06433 
06434     This routine just checks for media change sense/asc/ascq and
06435     also for other events, such as bus resets.  this is used to
06436     determine if the device behaviour has changed, to allow for
06437     read and write operations to be allowed and/or disallowed.
06438 
06439 Arguments:
06440 
06441     ISSUE-2000/3/30-henrygab - not fully doc'd
06442 
06443 Return Value:
06444 
06445     NTSTATUS
06446 
06447 --*/
06448 
06449 VOID
06450 NTAPI
06451 CdRomMmcErrorHandler(
06452     IN PDEVICE_OBJECT Fdo,
06453     IN PSCSI_REQUEST_BLOCK Srb,
06454     OUT PNTSTATUS Status,
06455     OUT PBOOLEAN Retry
06456     )
06457 {
06458     PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
06459     BOOLEAN queryCapabilities = FALSE;
06460 
06461     if (TEST_FLAG(Srb->SrbStatus, SRB_STATUS_AUTOSENSE_VALID)) {
06462         
06463         PCDROM_DATA cddata = (PCDROM_DATA)commonExtension->DriverData;
06464         PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer;
06465 
06466         //
06467         // the following sense keys could indicate a change in
06468         // capabilities.
06469         //
06470 
06471         //
06472         // we used to expect this to be serialized, and only hit from our
06473         // own routine. we now allow some requests to continue during our
06474         // processing of the capabilities update in order to allow
06475         // IoReadPartitionTable() to succeed.
06476         //
06477 
06478         switch (senseBuffer->SenseKey & 0xf) {
06479         
06480         case SCSI_SENSE_NOT_READY: {
06481             if (senseBuffer->AdditionalSenseCode ==
06482                 SCSI_ADSENSE_NO_MEDIA_IN_DEVICE) {
06483                 
06484                 if (cddata->Mmc.WriteAllowed) {
06485                     KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
06486                                "CdromErrorHandler: media removed, writes will be "
06487                                "failed until new media detected\n"));
06488                 }
06489 
06490                 // NOTE - REF #0002
06491                 cddata->Mmc.WriteAllowed = FALSE;
06492             } else
06493             if ((senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) &&
06494                 (senseBuffer->AdditionalSenseCodeQualifier ==
06495                  SCSI_SENSEQ_BECOMING_READY)) {
06496                 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
06497                            "CdromErrorHandler: media becoming ready, "
06498                            "SHOULD notify shell of change time by sending "
06499                            "GESN request immediately!\n"));
06500             }
06501             break;
06502         } // end SCSI_SENSE_NOT_READY
06503 
06504         case SCSI_SENSE_UNIT_ATTENTION: {
06505             switch (senseBuffer->AdditionalSenseCode) {
06506             case SCSI_ADSENSE_MEDIUM_CHANGED: {
06507                 
06508                 //
06509                 // always update if the medium may have changed
06510                 //
06511                 
06512                 // NOTE - REF #0002
06513                 cddata->Mmc.WriteAllowed = FALSE;
06514                 InterlockedCompareExchange(&(cddata->Mmc.UpdateState),
06515                                            CdromMmcUpdateRequired,
06516                                            CdromMmcUpdateComplete);
06517     
06518                 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
06519                            "CdromErrorHandler: media change detected, need to "
06520                            "update drive capabilities\n"));
06521                 break;
06522 
06523             } // end SCSI_ADSENSE_MEDIUM_CHANGED
06524             
06525             case SCSI_ADSENSE_BUS_RESET: {
06526                 
06527                 // NOTE - REF #0002
06528                 cddata->Mmc.WriteAllowed = FALSE;
06529                 InterlockedCompareExchange(&(cddata->Mmc.UpdateState),
06530                                            CdromMmcUpdateRequired,
06531                                            CdromMmcUpdateComplete);
06532 
06533                 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
06534                            "CdromErrorHandler: bus reset detected, need to "
06535                            "update drive capabilities\n"));
06536                 break;
06537 
06538             } // end SCSI_ADSENSE_BUS_RESET
06539 
06540             case SCSI_ADSENSE_OPERATOR_REQUEST: {
06541 
06542                 BOOLEAN b = FALSE;
06543                 
06544                 switch (senseBuffer->AdditionalSenseCodeQualifier) {
06545                 case SCSI_SENSEQ_MEDIUM_REMOVAL: {
06546                                         
06547                     //
06548                     // eject notification currently handled by classpnp
06549                     //
06550 
06551                     KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
06552                                "CdromErrorHandler: Eject requested by user\n"));
06553                     *Retry = TRUE;
06554                     *Status = STATUS_DEVICE_BUSY;
06555                     break;
06556                 }
06557 
06558                 case SCSI_SENSEQ_WRITE_PROTECT_DISABLE:
06559                     b = TRUE;
06560                 case SCSI_SENSEQ_WRITE_PROTECT_ENABLE: {
06561                     
06562                     KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
06563                                "CdromErrorHandler: Write protect %s requested "
06564                                "by user\n",
06565                                (b ? "disable" : "enable")));
06566                     *Retry = TRUE;
06567                     *Status = STATUS_DEVICE_BUSY;
06568                     // NOTE - REF #0002
06569                     cddata->Mmc.WriteAllowed = FALSE;
06570                     InterlockedCompareExchange(&(cddata->Mmc.UpdateState),
06571                                                CdromMmcUpdateRequired,
06572                                                CdromMmcUpdateComplete);
06573 
06574                 }
06575 
06576                 } // end of AdditionalSenseCodeQualifier switch
06577 
06578 
06579                 break;
06580 
06581             } // end SCSI_ADSENSE_OPERATOR_REQUEST
06582 
06583             default: {
06584                 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
06585                            "CdromErrorHandler: Unit attention %02x/%02x\n",
06586                            senseBuffer->AdditionalSenseCode,
06587                            senseBuffer->AdditionalSenseCodeQualifier));
06588                 break;
06589             }
06590 
06591             } // end of AdditionSenseCode switch
06592             break;
06593 
06594         } // end SCSI_SENSE_UNIT_ATTENTION
06595 
06596         case SCSI_SENSE_ILLEGAL_REQUEST: {
06597             if (senseBuffer->AdditionalSenseCode ==
06598                 SCSI_ADSENSE_WRITE_PROTECT) {
06599                 
06600                 if (cddata->Mmc.WriteAllowed) {
06601                     KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
06602                                "CdromErrorHandler: media was writable, but "
06603                                "failed request with WRITE_PROTECT error...\n"));
06604                 }
06605                 // NOTE - REF #0002
06606                 // do not update all the capabilities just because
06607                 // we can't write to the disc.
06608                 cddata->Mmc.WriteAllowed = FALSE;
06609             }
06610             break;
06611         } // end SCSI_SENSE_ILLEGAL_REQUEST
06612 
06613         } // end of SenseKey switch
06614 
06615     } // end of SRB_STATUS_AUTOSENSE_VALID
06616 }
06617 
06618 /*++
06619 
06620 Routine Description:
06621 
06622     This routine checks for a device-specific error handler
06623     and calls it if it exists.  This allows multiple drives
06624     that require their own error handler to co-exist.
06625 
06626 --*/
06627 VOID
06628 CdRomErrorHandler(
06629     PDEVICE_OBJECT DeviceObject,
06630     PSCSI_REQUEST_BLOCK Srb,
06631     NTSTATUS *Status,
06632     BOOLEAN *Retry
06633     )
06634 {
06635     PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
06636     PCDROM_DATA cddata = (PCDROM_DATA)commonExtension->DriverData;
06637     PSENSE_DATA sense = Srb->SenseInfoBuffer;
06638 
06639     if ((Srb->SenseInfoBufferLength >=
06640          RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA,AdditionalSenseCodeQualifier)) &&
06641         TEST_FLAG(Srb->SrbStatus, SRB_STATUS_AUTOSENSE_VALID)) {
06642 
06643         //
06644         //  Many non-WHQL certified drives (mostly CD-RW) return
06645         //  2/4/0 when they have no media instead of the obvious
06646         //  choice of:
06647         //
06648         //      SCSI_SENSE_NOT_READY/SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
06649         //
06650         //  These drives should not pass WHQL certification due
06651         //  to this discrepency.
06652         //
06653         //  However, we have to retry on 2/4/0 (Not ready, LUN not ready,
06654         //  no info) and also 3/2/0 (no seek complete).
06655         //
06656         //  These conditions occur when the shell tries to examine an
06657         //  injected CD (e.g. for autoplay) before the CD is spun up.
06658         //
06659         //  The drive should be returning an ASCQ of SCSI_SENSEQ_BECOMING_READY
06660         //  (0x01) in order to comply with WHQL standards.
06661         //
06662         //  The default retry timeout of one second is acceptable to balance
06663         //  these discrepencies.  don't modify the status, though....
06664         //
06665 
06666         if (((sense->SenseKey & 0xf) == SCSI_SENSE_NOT_READY) &&
06667             (sense->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) &&
06668             (sense->AdditionalSenseCodeQualifier == SCSI_SENSEQ_CAUSE_NOT_REPORTABLE)
06669             ) {
06670 
06671             *Retry = TRUE;
06672 
06673         } else if (((sense->SenseKey & 0xf) == SCSI_SENSE_MEDIUM_ERROR) &&
06674                    (sense->AdditionalSenseCode == 0x2) &&
06675                    (sense->AdditionalSenseCodeQualifier == 0x0)
06676                    ) {
06677 
06678             *Retry = TRUE;
06679 
06680         } else if ((sense->AdditionalSenseCode == 0x57) &&
06681                    (sense->AdditionalSenseCodeQualifier == 0x00)
06682                    ) {
06683 
06684             //
06685             // UNABLE_TO_RECOVER_TABLE_OF_CONTENTS
06686             // the Matshita CR-585 returns this for all read commands
06687             // on blank CD-R and CD-RW media, and we need to handle
06688             // this for READ_CD detection ability.
06689             //
06690             
06691             *Retry = FALSE;
06692             *Status = STATUS_UNRECOGNIZED_MEDIA;
06693 
06694         }
06695 
06696     }
06697 
06698     //
06699     // tail recursion in both cases takes no stack
06700     //
06701 
06702     if (cddata->ErrorHandler) {
06703         cddata->ErrorHandler(DeviceObject, Srb, Status, Retry);
06704     }
06705     return;
06706 }
06707 
06708 
06709 /*++
06710 
06711 Routine Description:
06712 
06713     This routine is called for a shutdown and flush IRPs.
06714     These are sent by the system before it actually shuts
06715     down or when the file system does a flush.
06716 
06717 Arguments:
06718 
06719     DriverObject - Pointer to device object to being shutdown by system.
06720 
06721     Irp - IRP involved.
06722 
06723 Return Value:
06724 
06725     NT Status
06726 
06727 --*/
06728 NTSTATUS
06729 CdRomShutdownFlush(
06730     IN PDEVICE_OBJECT DeviceObject,
06731     IN PIRP Irp
06732     )
06733 {
06734     IoMarkIrpPending(Irp);
06735     IoStartPacket(DeviceObject, Irp, NULL, NULL);
06736     return STATUS_PENDING;
06737 
06738 }
06739 
06740 /*++
06741 
06742 Routine Description:
06743 
06744     This routine is called for intermediate work a shutdown or
06745     flush IRPs would need to do.  We just want to free our resources
06746     and return STATUS_MORE_PROCESSING_REQUIRED.
06747 
06748 Arguments:
06749 
06750     DeviceObject - NULL?
06751 
06752     Irp - IRP to free
06753     
06754     Context - NULL
06755 
06756 Return Value:
06757 
06758     NT Status
06759 
06760 --*/
06761 NTSTATUS
06762 NTAPI
06763 CdRomShutdownFlushCompletion(
06764     IN PDEVICE_OBJECT Fdo,
06765     IN PIRP NewIrp,
06766     IN PIRP OriginalIrp 
06767     )
06768 {
06769     PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
06770     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
06771     PIO_STACK_LOCATION originalIrpStack;
06772     ULONG_PTR iteration;
06773     NTSTATUS status = STATUS_SUCCESS;
06774     
06775     ASSERT(OriginalIrp);
06776 
06777     originalIrpStack = IoGetCurrentIrpStackLocation(OriginalIrp);
06778 
06779     //
06780     // always use a new irp so we can call
06781     // CdRomCompleteIrpAndStartNextPacketSafely() from this routine.
06782     //
06783     
06784     if (NewIrp != NULL) {
06785         status = NewIrp->IoStatus.Status;
06786         IoFreeIrp(NewIrp);
06787         NewIrp = NULL;
06788     }
06789 
06790     if (!NT_SUCCESS(status)) {
06791         BAIL_OUT(OriginalIrp);
06792         goto SafeExit;
06793     }
06794     
06795     //
06796     // the current irpstack saves the counter which states
06797     // what part of the multi-part shutdown or flush we are in.
06798     //
06799 
06800     iteration = (ULONG_PTR)originalIrpStack->Parameters.Others.Argument1;
06801     iteration++;
06802     originalIrpStack->Parameters.Others.Argument1 = (PVOID)iteration;
06803 
06804     switch (iteration) {
06805     case 2:
06806         if (originalIrpStack->MajorFunction != IRP_MJ_SHUTDOWN) {
06807             //
06808             // then we don't want to send the unlock command
06809             // the incrementing of the state was done above.
06810             // return the completion routine's result.
06811             //
06812             return CdRomShutdownFlushCompletion(Fdo, NULL, OriginalIrp);
06813         }
06814         // else fall through....
06815 
06816     case 1: {
06817         
06818         PIRP                newIrp = NULL;
06819         PSCSI_REQUEST_BLOCK newSrb = NULL;
06820         PCDB                newCdb = NULL;
06821         PIO_STACK_LOCATION  newIrpStack = NULL;
06822         ULONG               isRemoved;
06823 
06824         newIrp = IoAllocateIrp((CCHAR)(Fdo->StackSize+1), FALSE);
06825         if (newIrp == NULL) {
06826             BAIL_OUT(OriginalIrp);
06827             status = STATUS_INSUFFICIENT_RESOURCES;
06828             goto SafeExit;
06829         }
06830         newSrb = ExAllocatePoolWithTag(NonPagedPool,
06831                                         sizeof(SCSI_REQUEST_BLOCK),
06832                                         CDROM_TAG_SRB);
06833         if (newSrb == NULL) {
06834             IoFreeIrp(newIrp);
06835             BAIL_OUT(OriginalIrp);
06836             status = STATUS_INSUFFICIENT_RESOURCES;
06837             goto SafeExit;
06838         }
06839         
06840         //
06841         // ClassIoComplete will free the SRB, but we need a routine
06842         // that will free the irp.  then just call ClassSendAsync,
06843         // and don't care about the return value, since the completion
06844         // routine will be called anyways.
06845         //
06846 
06847         IoSetNextIrpStackLocation(newIrp);
06848         newIrpStack = IoGetCurrentIrpStackLocation(newIrp);
06849         newIrpStack->DeviceObject = Fdo;
06850         IoSetCompletionRoutine(newIrp,
06851                                (PIO_COMPLETION_ROUTINE)CdRomShutdownFlushCompletion,
06852                                OriginalIrp,
06853                                TRUE, TRUE, TRUE);
06854         IoSetNextIrpStackLocation(newIrp);
06855         newIrpStack = IoGetCurrentIrpStackLocation(newIrp);
06856         newIrpStack->DeviceObject = Fdo;
06857 
06858         //
06859         // setup the request
06860         //
06861 
06862         RtlZeroMemory(newSrb, sizeof(SCSI_REQUEST_BLOCK));
06863         newCdb = (PCDB)(newSrb->Cdb);
06864         
06865         newSrb->QueueTag = SP_UNTAGGED;
06866         newSrb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
06867         newSrb->Function = SRB_FUNCTION_EXECUTE_SCSI;
06868 
06869         //
06870         // tell classpnp not to call StartNextPacket()
06871         //
06872 
06873         newSrb->SrbFlags = SRB_FLAGS_DONT_START_NEXT_PACKET;
06874 
06875         if (iteration == 1) {
06876 
06877             //
06878             // first synchronize the cache
06879             //
06880             
06881             newSrb->TimeOutValue = fdoExtension->TimeOutValue * 4;
06882             newSrb->CdbLength = 10;
06883             newCdb->SYNCHRONIZE_CACHE10.OperationCode = SCSIOP_SYNCHRONIZE_CACHE;
06884             
06885         } else if (iteration == 2) {
06886 
06887             //
06888             // then unlock the medium
06889             //
06890 
06891             ASSERT( originalIrpStack->MajorFunction == IRP_MJ_SHUTDOWN );
06892             
06893             newSrb->TimeOutValue = fdoExtension->TimeOutValue;
06894             newSrb->CdbLength = 6;
06895             newCdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
06896             newCdb->MEDIA_REMOVAL.Prevent = FALSE;
06897             
06898         }
06899 
06900 
06901         isRemoved = ClassAcquireRemoveLock(Fdo, newIrp);
06902         if (isRemoved) {
06903             IoFreeIrp(newIrp);
06904             ExFreePool(newSrb);
06905             ClassReleaseRemoveLock(Fdo, newIrp);
06906             BAIL_OUT(OriginalIrp);
06907             status = STATUS_DEVICE_DOES_NOT_EXIST;
06908             goto SafeExit;
06909         }
06910         ClassSendSrbAsynchronous(Fdo, newSrb, newIrp, NULL, 0, FALSE);
06911         break;
06912     }
06913 
06914     case 3: {
06915 
06916         PSCSI_REQUEST_BLOCK srb;
06917         PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(OriginalIrp);
06918         
06919         //
06920         // forward this request to the device appropriately,
06921         // don't use this completion routine anymore...
06922         //
06923         
06924         srb = ExAllocatePoolWithTag(NonPagedPool,
06925                                     sizeof(SCSI_REQUEST_BLOCK),
06926                                     CDROM_TAG_SRB);
06927         if (srb == NULL) {
06928             BAIL_OUT(OriginalIrp);
06929             status = STATUS_INSUFFICIENT_RESOURCES;
06930             goto SafeExit;
06931         }
06932 
06933         RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
06934         srb->Length = SCSI_REQUEST_BLOCK_SIZE;
06935         srb->TimeOutValue = fdoExtension->TimeOutValue * 4;
06936         srb->QueueTag = SP_UNTAGGED;
06937         srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
06938         srb->SrbFlags = fdoExtension->SrbFlags;
06939         srb->CdbLength = 0;
06940         srb->OriginalRequest = OriginalIrp;
06941 
06942         if (originalIrpStack->MajorFunction == IRP_MJ_SHUTDOWN) {
06943             srb->Function = SRB_FUNCTION_SHUTDOWN;
06944         } else {
06945             srb->Function = SRB_FUNCTION_FLUSH;
06946         }
06947 
06948         //
06949         // Set up IoCompletion routine address.
06950         //
06951 
06952         IoSetCompletionRoutine(OriginalIrp,
06953                                ClassIoComplete,
06954                                srb,
06955                                TRUE, TRUE, TRUE);
06956 
06957         //
06958         // Set the retry count to zero.
06959         //
06960 
06961         originalIrpStack->Parameters.Others.Argument4 = (PVOID) 0;
06962 
06963         //
06964         // Get next stack location and set major function code.
06965         //
06966 
06967         nextIrpStack->MajorFunction = IRP_MJ_SCSI;
06968 
06969         //
06970         // Set up SRB for execute scsi request.
06971         // Save SRB address in next stack for port driver.
06972         //
06973 
06974         nextIrpStack->Parameters.Scsi.Srb = srb;
06975 
06976         //
06977         // Call the port driver to process the request.
06978         //
06979 
06980         IoCallDriver(commonExtension->LowerDeviceObject, OriginalIrp);
06981         
06982         break;
06983 
06984     }
06985     default: {
06986         ASSERT(FALSE);
06987         break;
06988     }
06989 
06990     } // end switch
06991     
06992     status = STATUS_SUCCESS;
06993 
06994 SafeExit:
06995 
06996     if (!NT_SUCCESS(status)) {
06997         OriginalIrp->IoStatus.Status = status;
06998         CdRomCompleteIrpAndStartNextPacketSafely(Fdo, OriginalIrp);
06999     }
07000 
07001     //
07002     // always return STATUS_MORE_PROCESSING_REQUIRED, so noone else tries
07003     // to access the new irp that we free'd....
07004     //
07005 
07006     return STATUS_MORE_PROCESSING_REQUIRED;
07007 
07008 } // end CdromShutdownFlush()
07009 
07010 
07011 VOID
07012 CdromFakePartitionInfo(
07013     IN PCOMMON_DEVICE_EXTENSION CommonExtension,
07014     IN PIRP Irp
07015     )
07016 {
07017     PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
07018     ULONG ioctl = currentIrpStack->Parameters.DeviceIoControl.IoControlCode;
07019     PVOID systemBuffer = Irp->AssociatedIrp.SystemBuffer;
07020 
07021     ASSERT(systemBuffer);
07022 
07023     if ((ioctl != IOCTL_DISK_GET_DRIVE_LAYOUT) &&
07024         (ioctl != IOCTL_DISK_GET_DRIVE_LAYOUT_EX) &&
07025         (ioctl != IOCTL_DISK_GET_PARTITION_INFO) &&
07026         (ioctl != IOCTL_DISK_GET_PARTITION_INFO_EX)) {
07027         TraceLog((CdromDebugError,
07028                     "CdromFakePartitionInfo: unhandled ioctl %x\n", ioctl));
07029         Irp->IoStatus.Status = STATUS_INTERNAL_ERROR;
07030         Irp->IoStatus.Information = 0;
07031         CdRomCompleteIrpAndStartNextPacketSafely(CommonExtension->DeviceObject,
07032                                                  Irp);
07033         return;
07034     }
07035 
07036     //
07037     // nothing to fail from this point on, so set the size appropriately
07038     // and set irp's status to success.
07039     //
07040 
07041     TraceLog((CdromDebugWarning,
07042                 "CdromFakePartitionInfo: incoming ioctl %x\n", ioctl));
07043 
07044 
07045     Irp->IoStatus.Status = STATUS_SUCCESS;
07046     switch (ioctl) {
07047     case IOCTL_DISK_GET_DRIVE_LAYOUT:
07048         Irp->IoStatus.Information = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION,
07049                                                  PartitionEntry[1]);
07050         RtlZeroMemory(systemBuffer, FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION,
07051                                                  PartitionEntry[1]));
07052         break;
07053     case IOCTL_DISK_GET_DRIVE_LAYOUT_EX:
07054         Irp->IoStatus.Information = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX,
07055                                                  PartitionEntry[1]);
07056         RtlZeroMemory(systemBuffer, FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX,
07057                                                  PartitionEntry[1]));
07058         break;
07059     case IOCTL_DISK_GET_PARTITION_INFO:
07060         Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);
07061         RtlZeroMemory(systemBuffer, sizeof(PARTITION_INFORMATION));
07062         break;
07063     case IOCTL_DISK_GET_PARTITION_INFO_EX:
07064         Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION_EX);
07065         RtlZeroMemory(systemBuffer, sizeof(PARTITION_INFORMATION_EX));
07066         break;
07067     default:
07068         ASSERT(!"Invalid ioctl should not have reached this point\n");
07069         break;
07070     }
07071 
07072     //
07073     // if we are getting the drive layout, then we need to start by
07074     // adding some of the non-partition stuff that says we have
07075     // exactly one partition available.
07076     //
07077 
07078 
07079     if (ioctl == IOCTL_DISK_GET_DRIVE_LAYOUT) {
07080         
07081         PDRIVE_LAYOUT_INFORMATION layout;
07082         layout = (PDRIVE_LAYOUT_INFORMATION)systemBuffer;
07083         layout->PartitionCount = 1;
07084         layout->Signature = 1;
07085         systemBuffer = (PVOID)(layout->PartitionEntry);
07086         ioctl = IOCTL_DISK_GET_PARTITION_INFO;
07087         
07088     } else if (ioctl == IOCTL_DISK_GET_DRIVE_LAYOUT_EX) {
07089 
07090         PDRIVE_LAYOUT_INFORMATION_EX layoutEx;
07091         layoutEx = (PDRIVE_LAYOUT_INFORMATION_EX)systemBuffer;
07092         layoutEx->PartitionStyle = PARTITION_STYLE_MBR;
07093         layoutEx->PartitionCount = 1;
07094         layoutEx->Mbr.Signature = 1;
07095         systemBuffer = (PVOID)(layoutEx->PartitionEntry);
07096         ioctl = IOCTL_DISK_GET_PARTITION_INFO_EX;
07097 
07098     }
07099 
07100     //
07101     // NOTE: the local var 'ioctl' is now modified to either EX or
07102     // non-EX version. the local var 'systemBuffer' is now pointing
07103     // to the partition information structure.
07104     //
07105 
07106     if (ioctl == IOCTL_DISK_GET_PARTITION_INFO) {
07107 
07108         PPARTITION_INFORMATION partitionInfo;
07109         partitionInfo = (PPARTITION_INFORMATION)systemBuffer;
07110         partitionInfo->RewritePartition = FALSE;
07111         partitionInfo->RecognizedPartition = TRUE;
07112         partitionInfo->PartitionType = PARTITION_FAT32;
07113         partitionInfo->BootIndicator = FALSE;
07114         partitionInfo->HiddenSectors = 0;
07115         partitionInfo->StartingOffset.QuadPart = 0;
07116         partitionInfo->PartitionLength = CommonExtension->PartitionLength;
07117         partitionInfo->PartitionNumber = 0;
07118     
07119     } else {
07120 
07121         PPARTITION_INFORMATION_EX partitionInfo;
07122         partitionInfo = (PPARTITION_INFORMATION_EX)systemBuffer;
07123         partitionInfo->PartitionStyle = PARTITION_STYLE_MBR;
07124         partitionInfo->RewritePartition = FALSE;
07125         partitionInfo->Mbr.RecognizedPartition = TRUE;
07126         partitionInfo->Mbr.PartitionType = PARTITION_FAT32;
07127         partitionInfo->Mbr.BootIndicator = FALSE;
07128         partitionInfo->Mbr.HiddenSectors = 0;
07129         partitionInfo->StartingOffset.QuadPart = 0;
07130         partitionInfo->PartitionLength = CommonExtension->PartitionLength;
07131         partitionInfo->PartitionNumber = 0;
07132     
07133     }
07134     TraceLog((CdromDebugWarning,
07135                 "CdromFakePartitionInfo: finishing ioctl %x\n",
07136                 currentIrpStack->Parameters.DeviceIoControl.IoControlCode));
07137 
07138     //
07139     // complete the irp
07140     //
07141 
07142     CdRomCompleteIrpAndStartNextPacketSafely(CommonExtension->DeviceObject,
07143                                              Irp);
07144     return;
07145 
07146 }
07147 
07148 

Generated on Sun May 27 2012 04:28:15 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.