Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygencdrom.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)§orOffset)->Byte3; 02492 cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)§orOffset)->Byte2; 02493 cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)§orOffset)->Byte1; 02494 cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)§orOffset)->Byte0; 02495 02496 cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)§orCount)->Byte1; 02497 cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)§orCount)->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
1.7.6.1
|