Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

7137 lines
217 KiB

  1. /*--
  2. Copyright (C) Microsoft Corporation, 1991 - 1999
  3. Module Name:
  4. cdrom.c
  5. Abstract:
  6. The CDROM class driver tranlates IRPs to SRBs with embedded CDBs
  7. and sends them to its devices through the port driver.
  8. Environment:
  9. kernel mode only
  10. Notes:
  11. SCSI Tape, CDRom and Disk class drivers share common routines
  12. that can be found in the CLASS directory (..\ntos\dd\class).
  13. Revision History:
  14. --*/
  15. #include "stddef.h"
  16. #include "string.h"
  17. #include "ntddk.h"
  18. #include "ntddcdvd.h"
  19. #include "classpnp.h"
  20. #include "initguid.h"
  21. #include "ntddstor.h"
  22. #include "cdrom.h"
  23. #include "cdrom.tmh"
  24. #ifdef ALLOC_PRAGMA
  25. #pragma alloc_text(INIT, DriverEntry)
  26. #pragma alloc_text(PAGE, CdRomUnload)
  27. #pragma alloc_text(PAGE, CdRomAddDevice)
  28. #pragma alloc_text(PAGE, CdRomCreateDeviceObject)
  29. #pragma alloc_text(PAGE, CdRomStartDevice)
  30. #pragma alloc_text(PAGE, ScanForSpecial)
  31. #pragma alloc_text(PAGE, ScanForSpecialHandler)
  32. #pragma alloc_text(PAGE, CdRomRemoveDevice)
  33. #pragma alloc_text(PAGE, CdRomGetDeviceType)
  34. #pragma alloc_text(PAGE, CdRomReadWriteVerification)
  35. #pragma alloc_text(PAGE, CdRomGetDeviceParameter)
  36. #pragma alloc_text(PAGE, CdRomSetDeviceParameter)
  37. #pragma alloc_text(PAGE, CdRomPickDvdRegion)
  38. #pragma alloc_text(PAGE, CdRomIsPlayActive)
  39. #pragma alloc_text(PAGEHITA, HitachiProcessError)
  40. #pragma alloc_text(PAGEHIT2, HitachiProcessErrorGD2000)
  41. #pragma alloc_text(PAGETOSH, ToshibaProcessErrorCompletion)
  42. #pragma alloc_text(PAGETOSH, ToshibaProcessError)
  43. #endif
  44. #define IS_WRITE_REQUEST(irpStack) \
  45. (irpStack->MajorFunction == IRP_MJ_WRITE)
  46. #define IS_READ_WRITE_REQUEST(irpStack) \
  47. ((irpStack->MajorFunction == IRP_MJ_READ) || \
  48. (irpStack->MajorFunction == IRP_MJ_WRITE) || \
  49. ((irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) && \
  50. (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_RAW_READ)))
  51. NTSTATUS
  52. DriverEntry(
  53. IN PDRIVER_OBJECT DriverObject,
  54. IN PUNICODE_STRING RegistryPath
  55. )
  56. /*++
  57. Routine Description:
  58. This routine initializes the cdrom class driver.
  59. Arguments:
  60. DriverObject - Pointer to driver object created by system.
  61. RegistryPath - Pointer to the name of the services node for this driver.
  62. Return Value:
  63. The function value is the final status from the initialization operation.
  64. --*/
  65. {
  66. CLASS_INIT_DATA InitializationData;
  67. PCDROM_DRIVER_EXTENSION driverExtension;
  68. NTSTATUS status;
  69. PAGED_CODE();
  70. WPP_INIT_TRACING(DriverObject, RegistryPath);
  71. TraceLog((CdromDebugTrace,
  72. "CDROM.SYS DriverObject %p loading\n", DriverObject));
  73. status = IoAllocateDriverObjectExtension(DriverObject,
  74. CDROM_DRIVER_EXTENSION_ID,
  75. sizeof(CDROM_DRIVER_EXTENSION),
  76. &driverExtension);
  77. if (!NT_SUCCESS(status)) {
  78. TraceLog((CdromDebugWarning,
  79. "DriverEntry !! no DriverObjectExtension %x\n", status));
  80. return status;
  81. }
  82. //
  83. // always zero the memory, since we are now reloading the driver.
  84. //
  85. RtlZeroMemory(driverExtension, sizeof(CDROM_DRIVER_EXTENSION));
  86. //
  87. // Zero InitData
  88. //
  89. RtlZeroMemory (&InitializationData, sizeof(CLASS_INIT_DATA));
  90. //
  91. // Set sizes
  92. //
  93. InitializationData.InitializationDataSize = sizeof(CLASS_INIT_DATA);
  94. InitializationData.FdoData.DeviceExtensionSize = DEVICE_EXTENSION_SIZE;
  95. InitializationData.FdoData.DeviceType = FILE_DEVICE_CD_ROM;
  96. InitializationData.FdoData.DeviceCharacteristics =
  97. FILE_REMOVABLE_MEDIA | FILE_DEVICE_SECURE_OPEN;
  98. //
  99. // Set entry points
  100. //
  101. InitializationData.FdoData.ClassError = CdRomErrorHandler;
  102. InitializationData.FdoData.ClassInitDevice = CdRomInitDevice;
  103. InitializationData.FdoData.ClassStartDevice = CdRomStartDevice;
  104. InitializationData.FdoData.ClassStopDevice = CdRomStopDevice;
  105. InitializationData.FdoData.ClassRemoveDevice = CdRomRemoveDevice;
  106. InitializationData.FdoData.ClassReadWriteVerification = CdRomReadWriteVerification;
  107. InitializationData.FdoData.ClassDeviceControl = CdRomDeviceControlDispatch;
  108. InitializationData.FdoData.ClassPowerDevice = ClassSpinDownPowerHandler;
  109. InitializationData.FdoData.ClassShutdownFlush = CdRomShutdownFlush;
  110. InitializationData.FdoData.ClassCreateClose = NULL;
  111. InitializationData.ClassStartIo = CdRomStartIo;
  112. InitializationData.ClassAddDevice = CdRomAddDevice;
  113. InitializationData.ClassTick = CdRomTickHandler;
  114. InitializationData.ClassUnload = CdRomUnload;
  115. //
  116. // Call the class init routine
  117. //
  118. return ClassInitialize( DriverObject, RegistryPath, &InitializationData);
  119. } // end DriverEntry()
  120. VOID
  121. CdRomUnload(
  122. IN PDRIVER_OBJECT DriverObject
  123. )
  124. {
  125. PAGED_CODE();
  126. UNREFERENCED_PARAMETER(DriverObject);
  127. TraceLog((CdromDebugTrace,
  128. "CDROM.SYS DriverObject %p unloading\n", DriverObject));
  129. WPP_CLEANUP(DriverObject);
  130. return;
  131. } // end CdRomUnload()
  132. NTSTATUS
  133. CdRomAddDevice(
  134. IN PDRIVER_OBJECT DriverObject,
  135. IN PDEVICE_OBJECT PhysicalDeviceObject
  136. )
  137. /*++
  138. Routine Description:
  139. This routine creates and initializes a new FDO for the corresponding
  140. PDO. It may perform property queries on the FDO but cannot do any
  141. media access operations.
  142. Arguments:
  143. DriverObject - CDROM class driver object.
  144. Pdo - the physical device object we are being added to
  145. Return Value:
  146. status
  147. --*/
  148. {
  149. NTSTATUS status;
  150. PAGED_CODE();
  151. //
  152. // Get the address of the count of the number of cdroms already initialized.
  153. //
  154. status = CdRomCreateDeviceObject(DriverObject,
  155. PhysicalDeviceObject);
  156. //
  157. // Note: this always increments driver extension counter
  158. // it will eventually wrap, and fail additions
  159. // if an existing cdrom has the given number.
  160. // so unlikely that we won't even bother considering
  161. // this case, since the cure is quite likely worse
  162. // than the symptoms.
  163. //
  164. if(NT_SUCCESS(status)) {
  165. //
  166. // keep track of the total number of active cdroms in IoGet(),
  167. // as some programs use this to determine when they have found
  168. // all the cdroms in the system.
  169. //
  170. TraceLog((CdromDebugTrace, "CDROM.SYS Add succeeded\n"));
  171. IoGetConfigurationInformation()->CdRomCount++;
  172. } else {
  173. TraceLog((CdromDebugWarning,
  174. "CDROM.SYS Add failed! %x\n", status));
  175. }
  176. return status;
  177. }
  178. NTSTATUS
  179. CdRomCreateDeviceObject(
  180. IN PDRIVER_OBJECT DriverObject,
  181. IN PDEVICE_OBJECT PhysicalDeviceObject
  182. )
  183. /*++
  184. Routine Description:
  185. This routine creates an object for the device and then calls the
  186. SCSI port driver for media capacity and sector size.
  187. Arguments:
  188. DriverObject - Pointer to driver object created by system.
  189. PortDeviceObject - to connect to SCSI port driver.
  190. DeviceCount - Number of previously installed CDROMs.
  191. PortCapabilities - Pointer to structure returned by SCSI port
  192. driver describing adapter capabilites (and limitations).
  193. LunInfo - Pointer to configuration information for this device.
  194. Return Value:
  195. NTSTATUS
  196. --*/
  197. {
  198. UCHAR ntNameBuffer[64];
  199. STRING ntNameString;
  200. NTSTATUS status;
  201. PDEVICE_OBJECT lowerDevice = NULL;
  202. PDEVICE_OBJECT deviceObject = NULL;
  203. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = NULL;
  204. PCDROM_DATA cdData = NULL;
  205. PCDROM_DRIVER_EXTENSION driverExtension = NULL;
  206. ULONG deviceNumber;
  207. CCHAR dosNameBuffer[64];
  208. CCHAR deviceNameBuffer[64];
  209. STRING deviceNameString;
  210. STRING dosString;
  211. UNICODE_STRING dosUnicodeString;
  212. UNICODE_STRING unicodeString;
  213. PAGED_CODE();
  214. //
  215. // Claim the device. Note that any errors after this
  216. // will goto the generic handler, where the device will
  217. // be released.
  218. //
  219. lowerDevice = IoGetAttachedDeviceReference(PhysicalDeviceObject);
  220. status = ClassClaimDevice(lowerDevice, FALSE);
  221. if(!NT_SUCCESS(status)) {
  222. //
  223. // Someone already had this device - we're in trouble
  224. //
  225. ObDereferenceObject(lowerDevice);
  226. return status;
  227. }
  228. //
  229. // Create device object for this device by first getting a unique name
  230. // for the device and then creating it.
  231. //
  232. driverExtension = IoGetDriverObjectExtension(DriverObject,
  233. CDROM_DRIVER_EXTENSION_ID);
  234. ASSERT(driverExtension != NULL);
  235. //
  236. // InterlockedCdRomCounter is biased by 1.
  237. //
  238. deviceNumber = InterlockedIncrement(&driverExtension->InterlockedCdRomCounter) - 1;
  239. sprintf(ntNameBuffer, "\\Device\\CdRom%d", deviceNumber);
  240. status = ClassCreateDeviceObject(DriverObject,
  241. ntNameBuffer,
  242. PhysicalDeviceObject,
  243. TRUE,
  244. &deviceObject);
  245. if (!NT_SUCCESS(status)) {
  246. TraceLog((CdromDebugWarning,
  247. "CreateCdRomDeviceObjects: Can not create device %s\n",
  248. ntNameBuffer));
  249. goto CreateCdRomDeviceObjectExit;
  250. }
  251. //
  252. // Indicate that IRPs should include MDLs.
  253. //
  254. SET_FLAG(deviceObject->Flags, DO_DIRECT_IO);
  255. fdoExtension = deviceObject->DeviceExtension;
  256. //
  257. // Back pointer to device object.
  258. //
  259. fdoExtension->CommonExtension.DeviceObject = deviceObject;
  260. //
  261. // This is the physical device.
  262. //
  263. fdoExtension->CommonExtension.PartitionZeroExtension = fdoExtension;
  264. //
  265. // Initialize lock count to zero. The lock count is used to
  266. // disable the ejection mechanism when media is mounted.
  267. //
  268. fdoExtension->LockCount = 0;
  269. //
  270. // Save system cdrom number
  271. //
  272. fdoExtension->DeviceNumber = deviceNumber;
  273. //
  274. // Set the alignment requirements for the device based on the
  275. // host adapter requirements
  276. //
  277. if (lowerDevice->AlignmentRequirement > deviceObject->AlignmentRequirement) {
  278. deviceObject->AlignmentRequirement = lowerDevice->AlignmentRequirement;
  279. }
  280. //
  281. // Save the device descriptors
  282. //
  283. fdoExtension->AdapterDescriptor = NULL;
  284. fdoExtension->DeviceDescriptor = NULL;
  285. //
  286. // Clear the SrbFlags and disable synchronous transfers
  287. //
  288. fdoExtension->SrbFlags = SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
  289. //
  290. // Finally, attach to the PDO
  291. //
  292. fdoExtension->LowerPdo = PhysicalDeviceObject;
  293. fdoExtension->CommonExtension.LowerDeviceObject =
  294. IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject);
  295. if(fdoExtension->CommonExtension.LowerDeviceObject == NULL) {
  296. //
  297. // Uh - oh, we couldn't attach
  298. // cleanup and return
  299. //
  300. status = STATUS_UNSUCCESSFUL;
  301. goto CreateCdRomDeviceObjectExit;
  302. }
  303. //
  304. // CdRom uses an extra stack location for synchronizing it's start io
  305. // routine
  306. //
  307. deviceObject->StackSize++;
  308. //
  309. // cdData is used a few times below
  310. //
  311. cdData = fdoExtension->CommonExtension.DriverData;
  312. //
  313. // For NTMS to be able to easily determine drives-drv. letter matches.
  314. //
  315. status = CdRomCreateWellKnownName( deviceObject );
  316. if (!NT_SUCCESS(status)) {
  317. TraceLog((CdromDebugWarning,
  318. "CdromCreateDeviceObjects: unable to create symbolic "
  319. "link for device %wZ\n", &fdoExtension->CommonExtension.DeviceName));
  320. TraceLog((CdromDebugWarning,
  321. "CdromCreateDeviceObjects: (non-fatal error)\n"));
  322. }
  323. ClassUpdateInformationInRegistry(deviceObject, "CdRom",
  324. fdoExtension->DeviceNumber, NULL, 0);
  325. //
  326. // from above IoGetAttachedDeviceReference
  327. //
  328. ObDereferenceObject(lowerDevice);
  329. //
  330. // need to init timerlist here in case a remove occurs
  331. // without a start, since we check the list is empty on remove.
  332. //
  333. cdData->DelayedRetryIrp = NULL;
  334. cdData->DelayedRetryInterval = 0;
  335. //
  336. // need this to be initialized for RPC Phase 1 drives (rpc0)
  337. //
  338. KeInitializeMutex(&cdData->Rpc0RegionMutex, 0);
  339. //
  340. // The device is initialized properly - mark it as such.
  341. //
  342. CLEAR_FLAG(deviceObject->Flags, DO_DEVICE_INITIALIZING);
  343. return(STATUS_SUCCESS);
  344. CreateCdRomDeviceObjectExit:
  345. //
  346. // Release the device since an error occured.
  347. //
  348. // ClassClaimDevice(PortDeviceObject,
  349. // LunInfo,
  350. // TRUE,
  351. // NULL);
  352. //
  353. // from above IoGetAttachedDeviceReference
  354. //
  355. ObDereferenceObject(lowerDevice);
  356. if (deviceObject != NULL) {
  357. IoDeleteDevice(deviceObject);
  358. }
  359. return status;
  360. } // end CreateCdRomDeviceObject()
  361. NTSTATUS
  362. CdRomInitDevice(
  363. IN PDEVICE_OBJECT Fdo
  364. )
  365. /*++
  366. Routine Description:
  367. This routine will complete the cd-rom initialization. This includes
  368. allocating sense info buffers and srb s-lists, reading drive capacity
  369. and setting up Media Change Notification (autorun).
  370. This routine will not clean up allocate resources if it fails - that
  371. is left for device stop/removal
  372. Arguments:
  373. Fdo - a pointer to the functional device object for this device
  374. Return Value:
  375. status
  376. --*/
  377. {
  378. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  379. PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
  380. PCLASS_DRIVER_EXTENSION driverExtension = ClassGetDriverExtension(
  381. Fdo->DriverObject);
  382. PVOID senseData = NULL;
  383. ULONG timeOut;
  384. PCDROM_DATA cddata;
  385. BOOLEAN changerDevice;
  386. BOOLEAN isMmcDevice = FALSE;
  387. ULONG bps;
  388. ULONG lastBit;
  389. NTSTATUS status;
  390. PAGED_CODE();
  391. //
  392. // Build the lookaside list for srb's for the physical disk. Should only
  393. // need a couple.
  394. //
  395. ClassInitializeSrbLookasideList(&(fdoExtension->CommonExtension),
  396. CDROM_SRB_LIST_SIZE);
  397. //
  398. // Allocate request sense buffer.
  399. //
  400. senseData = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  401. SENSE_BUFFER_SIZE,
  402. CDROM_TAG_SENSE_INFO);
  403. if (senseData == NULL) {
  404. //
  405. // The buffer cannot be allocated.
  406. //
  407. status = STATUS_INSUFFICIENT_RESOURCES;
  408. goto CdRomInitDeviceExit;
  409. }
  410. //
  411. // Set the sense data pointer in the device extension.
  412. //
  413. fdoExtension->SenseData = senseData;
  414. //
  415. // CDROMs are not partitionable so starting offset is 0.
  416. //
  417. commonExtension->StartingOffset.LowPart = 0;
  418. commonExtension->StartingOffset.HighPart = 0;
  419. //
  420. // Set timeout value in seconds.
  421. //
  422. timeOut = ClassQueryTimeOutRegistryValue(Fdo);
  423. if (timeOut) {
  424. fdoExtension->TimeOutValue = timeOut;
  425. } else {
  426. fdoExtension->TimeOutValue = SCSI_CDROM_TIMEOUT;
  427. }
  428. cddata = (PCDROM_DATA)(commonExtension->DriverData);
  429. //
  430. // Set up media change support defaults.
  431. //
  432. KeInitializeSpinLock(&cddata->DelayedRetrySpinLock);
  433. cddata->DelayedRetryIrp = NULL;
  434. cddata->DelayedRetryInterval = 0;
  435. cddata->Mmc.WriteAllowed = FALSE;
  436. //
  437. // Scan for controllers that require special processing.
  438. //
  439. ScanForSpecial(Fdo);
  440. //
  441. // Determine if the drive is MMC-Capable
  442. //
  443. CdRomIsDeviceMmcDevice(Fdo, &isMmcDevice);
  444. if (!isMmcDevice) {
  445. SET_FLAG(Fdo->Characteristics, FILE_READ_ONLY_DEVICE);
  446. } else {
  447. //
  448. // the drive supports at least a subset of MMC commands
  449. // (and therefore supports READ_CD, etc...)
  450. //
  451. cddata->Mmc.IsMmc = TRUE;
  452. //
  453. // allocate a buffer for all the capabilities and such
  454. //
  455. status = CdRomAllocateMmcResources(Fdo);
  456. if (!NT_SUCCESS(status)) {
  457. goto CdRomInitDeviceExit;
  458. }
  459. #if 0
  460. //
  461. // determine all the various media types from the profiles feature
  462. //
  463. {
  464. PFEATURE_DATA_PROFILE_LIST profileHeader;
  465. ULONG mediaTypes = 0;
  466. ULONG i;
  467. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugError,
  468. "Checking all profiles for media types supported.\n"
  469. ));
  470. profileHeader = CdRomFindFeaturePage(cddata->Mmc.CapabilitiesBuffer,
  471. cddata->Mmc.CapabilitiesBufferSize,
  472. FeatureProfileList);
  473. if (profileHeader == NULL) {
  474. //
  475. // if profiles don't exist, there is something seriously
  476. // wrong with this command -- it's either not a cdrom or
  477. // one that hasn't implemented the spec correctly. exit
  478. // now while we have the chance to do so safely.
  479. //
  480. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugError,
  481. "CdromDevice supports GET_CONFIGURATION, but "
  482. "doesn't provide profiles for PDO %p!\n",
  483. fdoExtension->LowerPdo));
  484. status = STATUS_DEVICE_CONFIGURATION_ERROR;
  485. goto CdRomInitDeviceExit;
  486. }
  487. for (i = 0; i < MAX_CDROM_MEDIA_TYPES; i++) {
  488. BOOLEAN profileFound;
  489. CdRomFindProfileInProfiles(profileHeader,
  490. MediaProfileMatch[i].Profile,
  491. &profileFound);
  492. if (profileFound) {
  493. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugError,
  494. "CdromInit -> Found Profile %x => Media %x "
  495. "(%x total)\n",
  496. MediaProfileMatch[i].Profile,
  497. MediaProfileMatch[i].Media,
  498. mediaTypes + 1
  499. ));
  500. cddata->Mmc.MediaProfileMatches[mediaTypes] =
  501. MediaProfileMatch[i];
  502. mediaTypes++;
  503. }
  504. }
  505. if (mediaTypes == 0) {
  506. //
  507. // if profiles don't exist, there is something seriously
  508. // wrong with this command -- it's either not a cdrom or
  509. // one that hasn't implemented the spec correctly. exit
  510. // now while we have the chance to do so safely.
  511. //
  512. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugError,
  513. "CdromDevice supports GET_CONFIGURATION, but "
  514. "doesn't support any of the standard profiles "
  515. "for PDO %p!\n", fdoExtension->LowerPdo));
  516. status = STATUS_DEVICE_CONFIGURATION_ERROR;
  517. goto CdRomInitDeviceExit;
  518. }
  519. cddata->Mmc.MediaTypes = mediaTypes;
  520. }
  521. #endif // media checks, and all failure paths due to bad firmware.
  522. //
  523. // if the drive supports target defect management and sector-addressable
  524. // writes, then we should allow writes to the media.
  525. //
  526. if (CdRomFindFeaturePage(cddata->Mmc.CapabilitiesBuffer,
  527. cddata->Mmc.CapabilitiesBufferSize,
  528. FeatureDefectManagement) &&
  529. CdRomFindFeaturePage(cddata->Mmc.CapabilitiesBuffer,
  530. cddata->Mmc.CapabilitiesBufferSize,
  531. FeatureRandomWritable)) {
  532. //
  533. // the drive is target defect managed, and supports random writes
  534. // on sector-aligment. allow writes to occur by setting the error
  535. // handler to point to a private media change detection handler.
  536. //
  537. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  538. "Found a WRITE capable device: %p\n", Fdo));
  539. //
  540. // the write specific pages have been found --
  541. // set the error handler and set it to require an update!
  542. //
  543. cddata->Mmc.UpdateState = CdromMmcUpdateRequired;
  544. cddata->ErrorHandler = CdRomMmcErrorHandler;
  545. }
  546. //
  547. // ISSUE-2000/4/4-henrygab - mmc-compliant compliant drives should
  548. // be initialized based upon reported
  549. // capabilities, such as CSS, Analogue Audio,
  550. // READ_CD capabilities, and (possibly) even
  551. // drive capacity information.
  552. //
  553. TraceLog((CdromDebugWarning,
  554. "Defaulting to READ_CD because device %p is MMC compliant\n",
  555. Fdo));
  556. SET_FLAG(fdoExtension->DeviceFlags, DEV_SAFE_START_UNIT);
  557. SET_FLAG(cddata->XAFlags, XA_USE_READ_CD);
  558. }
  559. //
  560. // Set the default geometry for the cdrom to match what NT 4 used.
  561. // Classpnp will use these values to compute the cylinder count rather
  562. // than using it's NT 5.0 defaults.
  563. //
  564. fdoExtension->DiskGeometry.TracksPerCylinder = 0x40;
  565. fdoExtension->DiskGeometry.SectorsPerTrack = 0x20;
  566. //
  567. // Do READ CAPACITY. This SCSI command returns the last sector address
  568. // on the device and the bytes per sector. These are used to calculate
  569. // the drive capacity in bytes.
  570. //
  571. // NOTE: This should be change to send the Srb synchronously, then
  572. // call CdRomInterpretReadCapacity() to properly setup the defaults.
  573. //
  574. status = ClassReadDriveCapacity(Fdo);
  575. bps = fdoExtension->DiskGeometry.BytesPerSector;
  576. if (!NT_SUCCESS(status) || !bps) {
  577. TraceLog((CdromDebugWarning,
  578. "CdRomStartDevice: Can't read capacity for device %wZ\n",
  579. &(fdoExtension->CommonExtension.DeviceName)));
  580. //
  581. // Set disk geometry to default values (per ISO 9660).
  582. //
  583. bps = 2048;
  584. fdoExtension->SectorShift = 11;
  585. commonExtension->PartitionLength.QuadPart = (LONGLONG)(0x7fffffff);
  586. } else {
  587. //
  588. // Insure that bytes per sector is a power of 2
  589. // This corrects a problem with the HP 4020i CDR where it
  590. // returns an incorrect number for bytes per sector.
  591. //
  592. lastBit = (ULONG) -1;
  593. while (bps) {
  594. lastBit++;
  595. bps = bps >> 1;
  596. }
  597. bps = 1 << lastBit;
  598. }
  599. fdoExtension->DiskGeometry.BytesPerSector = bps;
  600. TraceLog((CdromDebugTrace, "CdRomInitDevice: Calc'd bps = %x\n", bps));
  601. ClassInitializeMediaChangeDetection(fdoExtension, "CdRom");
  602. //
  603. // test for audio read capabilities
  604. //
  605. TraceLog((CdromDebugWarning,
  606. "Detecting XA_READ capabilities\n"));
  607. if (CdRomGetDeviceType(Fdo) == FILE_DEVICE_DVD) {
  608. TraceLog((CdromDebugWarning,
  609. "CdRomInitDevice: DVD Devices require START_UNIT\n"));
  610. //
  611. // all DVD devices must support the READ_CD command
  612. //
  613. TraceLog((CdromDebugWarning,
  614. "CdRomDetermineRawReadCapabilities: DVD devices "
  615. "support READ_CD command for FDO %p\n", Fdo));
  616. SET_FLAG(fdoExtension->DeviceFlags, DEV_SAFE_START_UNIT);
  617. SET_FLAG(cddata->XAFlags, XA_USE_READ_CD);
  618. status = STATUS_SUCCESS;
  619. } else if ((fdoExtension->DeviceDescriptor->BusType != BusTypeScsi) &&
  620. (fdoExtension->DeviceDescriptor->BusType != BusTypeAta) &&
  621. (fdoExtension->DeviceDescriptor->BusType != BusTypeAtapi) &&
  622. (fdoExtension->DeviceDescriptor->BusType != BusTypeUnknown)
  623. ) {
  624. //
  625. // devices on the newer busses must support READ_CD command
  626. //
  627. TraceLog((CdromDebugWarning,
  628. "CdRomDetermineRawReadCapabilities: Devices for newer "
  629. "busses must support READ_CD command for FDO %p, Bus %x\n",
  630. Fdo, fdoExtension->DeviceDescriptor->BusType));
  631. SET_FLAG(fdoExtension->DeviceFlags, DEV_SAFE_START_UNIT);
  632. SET_FLAG(cddata->XAFlags, XA_USE_READ_CD);
  633. }
  634. //
  635. // now clear all our READ_CD flags if the drive should have supported
  636. // it, but we are not sure it actually does. we still won't query
  637. // the drive more than one time if it supports the command.
  638. //
  639. if (TEST_FLAG(cddata->HackFlags, CDROM_HACK_FORCE_READ_CD_DETECTION)) {
  640. TraceLog((CdromDebugWarning,
  641. "Forcing detection of READ_CD for FDO %p because "
  642. "testing showed some firmware did not properly support it\n",
  643. Fdo));
  644. CLEAR_FLAG(cddata->XAFlags, XA_USE_READ_CD);
  645. }
  646. //
  647. // read our READ_CD support in the registry if it was seeded.
  648. //
  649. {
  650. ULONG readCdSupported = 0;
  651. ClassGetDeviceParameter(fdoExtension,
  652. CDROM_SUBKEY_NAME,
  653. CDROM_READ_CD_NAME,
  654. &readCdSupported
  655. );
  656. if (readCdSupported != 0) {
  657. TraceLog((CdromDebugWarning,
  658. "Defaulting to READ_CD because previously detected "
  659. "that the device supports it for Fdo %p.\n",
  660. Fdo
  661. ));
  662. SET_FLAG(cddata->XAFlags, XA_USE_READ_CD);
  663. }
  664. }
  665. //
  666. // backwards-compatible hackish attempt to determine if the drive
  667. // supports any method of reading digital audio from the disc.
  668. //
  669. if (!TEST_FLAG(cddata->XAFlags, XA_USE_READ_CD)) {
  670. SCSI_REQUEST_BLOCK srb;
  671. PCDB cdb;
  672. ULONG length;
  673. PUCHAR buffer = NULL;
  674. ULONG count;
  675. //
  676. // ISSUE-2000/07/05-henrygab - use the mode page to determine
  677. // READ_CD support, then fall back on the below
  678. // (unreliable?) hack.
  679. //
  680. //
  681. // Build the MODE SENSE CDB. The data returned will be kept in the
  682. // device extension and used to set block size.
  683. //
  684. length = max(sizeof(ERROR_RECOVERY_DATA),sizeof(ERROR_RECOVERY_DATA10));
  685. buffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  686. length,
  687. CDROM_TAG_MODE_DATA);
  688. if (!buffer) {
  689. TraceLog((CdromDebugWarning,
  690. "CdRomDetermineRawReadCapabilities: cannot allocate "
  691. "buffer, so leaving for FDO %p\n", Fdo));
  692. status = STATUS_INSUFFICIENT_RESOURCES;
  693. goto CdRomInitDeviceExit;
  694. }
  695. for (count = 0; count < 2; count++) {
  696. if (count == 0) {
  697. length = sizeof(ERROR_RECOVERY_DATA);
  698. } else {
  699. length = sizeof(ERROR_RECOVERY_DATA10);
  700. }
  701. RtlZeroMemory(buffer, length);
  702. RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
  703. cdb = (PCDB)srb.Cdb;
  704. srb.TimeOutValue = fdoExtension->TimeOutValue;
  705. if (count == 0) {
  706. srb.CdbLength = 6;
  707. cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
  708. cdb->MODE_SENSE.PageCode = 0x1;
  709. // note: not setting DBD in order to get the block descriptor!
  710. cdb->MODE_SENSE.AllocationLength = (UCHAR)length;
  711. } else {
  712. srb.CdbLength = 10;
  713. cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
  714. cdb->MODE_SENSE10.PageCode = 0x1;
  715. // note: not setting DBD in order to get the block descriptor!
  716. cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(length >> 8);
  717. cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(length & 0xFF);
  718. }
  719. status = ClassSendSrbSynchronous(Fdo,
  720. &srb,
  721. buffer,
  722. length,
  723. FALSE);
  724. if (NT_SUCCESS(status) || (status == STATUS_DATA_OVERRUN)) {
  725. //
  726. // STATUS_DATA_OVERRUN means it's a newer drive with more info
  727. // to tell us, so it's probably able to support READ_CD
  728. //
  729. RtlZeroMemory(cdb, CDB12GENERIC_LENGTH);
  730. srb.CdbLength = 12;
  731. cdb->READ_CD.OperationCode = SCSIOP_READ_CD;
  732. status = ClassSendSrbSynchronous(Fdo,
  733. &srb,
  734. NULL,
  735. 0,
  736. FALSE);
  737. if (NT_SUCCESS(status) ||
  738. (status == STATUS_NO_MEDIA_IN_DEVICE) ||
  739. (status == STATUS_NONEXISTENT_SECTOR) ||
  740. (status == STATUS_UNRECOGNIZED_MEDIA)
  741. ) {
  742. //
  743. // READ_CD works
  744. //
  745. TraceLog((CdromDebugWarning,
  746. "CdRomDetermineRawReadCapabilities: Using "
  747. "READ_CD for FDO %p due to status %x\n",
  748. Fdo,
  749. status));
  750. SET_FLAG(cddata->XAFlags, XA_USE_READ_CD);
  751. //
  752. // ignore errors in saving this info
  753. //
  754. ClassSetDeviceParameter(fdoExtension,
  755. CDROM_SUBKEY_NAME,
  756. CDROM_READ_CD_NAME,
  757. 1
  758. );
  759. break; // out of the for loop
  760. }
  761. TraceLog((CdromDebugWarning,
  762. "CdRomDetermineRawReadCapabilities: Using "
  763. "%s-byte mode switching for FDO %p due to status "
  764. "%x returned for READ_CD\n",
  765. ((count == 0) ? "6" : "10"), Fdo, status));
  766. if (count == 0) {
  767. SET_FLAG(cddata->XAFlags, XA_USE_6_BYTE);
  768. RtlCopyMemory(&cddata->Header,
  769. buffer,
  770. sizeof(ERROR_RECOVERY_DATA));
  771. cddata->Header.ModeDataLength = 0;
  772. } else {
  773. SET_FLAG(cddata->XAFlags, XA_USE_10_BYTE);
  774. RtlCopyMemory(&cddata->Header10,
  775. buffer,
  776. sizeof(ERROR_RECOVERY_DATA10));
  777. cddata->Header10.ModeDataLength[0] = 0;
  778. cddata->Header10.ModeDataLength[1] = 0;
  779. }
  780. break; // out of for loop
  781. }
  782. TraceLog((CdromDebugWarning,
  783. "FDO %p failed %x byte mode sense, status %x\n",
  784. Fdo,
  785. ((count == 0) ? 6 : 10),
  786. status
  787. ));
  788. //
  789. // mode sense failed
  790. //
  791. } // end of for loop to try 6 and 10-byte mode sense
  792. if (count == 2) {
  793. //
  794. // nothing worked. we probably cannot support digital
  795. // audio extraction from this drive
  796. //
  797. TraceLog((CdromDebugWarning,
  798. "CdRomDetermineRawReadCapabilities: FDO %p "
  799. "cannot support READ_CD\n", Fdo));
  800. CLEAR_FLAG(cddata->XAFlags, XA_PLEXTOR_CDDA);
  801. CLEAR_FLAG(cddata->XAFlags, XA_NEC_CDDA);
  802. SET_FLAG(cddata->XAFlags, XA_NOT_SUPPORTED);
  803. } // end of count == 2
  804. //
  805. // free our resources
  806. //
  807. ExFreePool(buffer);
  808. //
  809. // set a successful status
  810. // (in case someone later checks this)
  811. //
  812. status = STATUS_SUCCESS;
  813. }
  814. //
  815. // Register interfaces for this device.
  816. //
  817. {
  818. UNICODE_STRING interfaceName;
  819. RtlInitUnicodeString(&interfaceName, NULL);
  820. status = IoRegisterDeviceInterface(fdoExtension->LowerPdo,
  821. (LPGUID) &CdRomClassGuid,
  822. NULL,
  823. &interfaceName);
  824. if(NT_SUCCESS(status)) {
  825. cddata->CdromInterfaceString = interfaceName;
  826. status = IoSetDeviceInterfaceState(
  827. &interfaceName,
  828. TRUE);
  829. if(!NT_SUCCESS(status)) {
  830. TraceLog((CdromDebugWarning,
  831. "CdromInitDevice: Unable to register cdrom "
  832. "DCA for fdo %p [%lx]\n",
  833. Fdo, status));
  834. }
  835. }
  836. }
  837. return(STATUS_SUCCESS);
  838. CdRomInitDeviceExit:
  839. CdRomDeAllocateMmcResources(Fdo);
  840. RtlZeroMemory(&(cddata->Mmc), sizeof(CDROM_MMC_EXTENSION));
  841. return status;
  842. }
  843. NTSTATUS
  844. CdRomStartDevice(
  845. IN PDEVICE_OBJECT Fdo
  846. )
  847. /*++
  848. Routine Description:
  849. This routine starts the timer for the cdrom
  850. Arguments:
  851. Fdo - a pointer to the functional device object for this device
  852. Return Value:
  853. status
  854. --*/
  855. {
  856. PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
  857. PCDROM_DATA cddata = (PCDROM_DATA)(commonExtension->DriverData);
  858. PDVD_COPY_PROTECT_KEY copyProtectKey;
  859. PDVD_RPC_KEY rpcKey;
  860. IO_STATUS_BLOCK ioStatus;
  861. ULONG bufferLen;
  862. // CdRomCreateWellKnownName(Fdo);
  863. //
  864. // if we have a DVD-ROM
  865. // if we have a rpc0 device
  866. // fake a rpc2 device
  867. // if device does not have a dvd region set
  868. // select a dvd region for the user
  869. //
  870. cddata->DvdRpc0Device = FALSE;
  871. //
  872. // since StartIo() will call IoStartNextPacket() on error, allowing
  873. // StartIo() to be non-recursive prevents stack overflow bugchecks in
  874. // severe error cases (such as fault-injection in the verifier).
  875. //
  876. // the only difference is that the thread context may be different
  877. // in StartIo() than in the caller of IoStartNextPacket().
  878. //
  879. IoSetStartIoAttributes(Fdo, TRUE, TRUE);
  880. //
  881. // check to see if we have a DVD device
  882. //
  883. if (CdRomGetDeviceType(Fdo) != FILE_DEVICE_DVD) {
  884. return STATUS_SUCCESS;
  885. }
  886. //
  887. // we got a DVD drive.
  888. // now, figure out if we have a RPC0 device
  889. //
  890. bufferLen = DVD_RPC_KEY_LENGTH;
  891. copyProtectKey =
  892. (PDVD_COPY_PROTECT_KEY)ExAllocatePoolWithTag(PagedPool,
  893. bufferLen,
  894. DVD_TAG_RPC2_CHECK);
  895. if (copyProtectKey == NULL) {
  896. return STATUS_INSUFFICIENT_RESOURCES;
  897. }
  898. //
  899. // get the device region
  900. //
  901. RtlZeroMemory (copyProtectKey, bufferLen);
  902. copyProtectKey->KeyLength = DVD_RPC_KEY_LENGTH;
  903. copyProtectKey->KeyType = DvdGetRpcKey;
  904. //
  905. // Build a request for READ_KEY
  906. //
  907. ClassSendDeviceIoControlSynchronous(
  908. IOCTL_DVD_READ_KEY,
  909. Fdo,
  910. copyProtectKey,
  911. DVD_RPC_KEY_LENGTH,
  912. DVD_RPC_KEY_LENGTH,
  913. FALSE,
  914. &ioStatus
  915. );
  916. if (!NT_SUCCESS(ioStatus.Status)) {
  917. //
  918. // we have a rpc0 device
  919. //
  920. // NOTE: THIS MODIFIES THE BEHAVIOR OF THE IOCTL
  921. //
  922. cddata->DvdRpc0Device = TRUE;
  923. TraceLog((CdromDebugWarning,
  924. "CdromStartDevice (%p): RPC Phase 1 drive detected\n",
  925. Fdo));
  926. //
  927. // note: we could force this chosen now, but it's better to reduce
  928. // the number of code paths that could be taken. always delay to
  929. // increase the percentage code coverage.
  930. //
  931. TraceLog((CdromDebugWarning,
  932. "CdromStartDevice (%p): Delay DVD Region Selection\n",
  933. Fdo));
  934. cddata->Rpc0SystemRegion = 0xff;
  935. cddata->Rpc0SystemRegionResetCount = DVD_MAX_REGION_RESET_COUNT;
  936. cddata->PickDvdRegion = 1;
  937. cddata->Rpc0RetryRegistryCallback = 1;
  938. ExFreePool(copyProtectKey);
  939. return STATUS_SUCCESS;
  940. } else {
  941. rpcKey = (PDVD_RPC_KEY) copyProtectKey->KeyData;
  942. //
  943. // TypeCode of zero means that no region has been set.
  944. //
  945. if (rpcKey->TypeCode == 0) {
  946. TraceLog((CdromDebugWarning,
  947. "CdromStartDevice (%p): must choose DVD region\n",
  948. Fdo));
  949. cddata->PickDvdRegion = 1;
  950. CdRomPickDvdRegion(Fdo);
  951. }
  952. }
  953. ExFreePool (copyProtectKey);
  954. return STATUS_SUCCESS;
  955. }
  956. NTSTATUS
  957. CdRomStopDevice(
  958. IN PDEVICE_OBJECT DeviceObject,
  959. IN UCHAR Type
  960. )
  961. {
  962. return STATUS_SUCCESS;
  963. }
  964. VOID
  965. CdRomStartIo(
  966. IN PDEVICE_OBJECT Fdo,
  967. IN PIRP Irp
  968. )
  969. {
  970. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  971. PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
  972. PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
  973. PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
  974. PIO_STACK_LOCATION irpStack;
  975. PIRP irp2 = NULL;
  976. ULONG transferPages;
  977. ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
  978. LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
  979. PCDROM_DATA cdData;
  980. PSCSI_REQUEST_BLOCK srb = NULL;
  981. PCDB cdb;
  982. PUCHAR senseBuffer = NULL;
  983. PVOID dataBuffer;
  984. NTSTATUS status;
  985. BOOLEAN use6Byte;
  986. KIRQL oldIrql;
  987. //
  988. // Mark IRP with status pending.
  989. //
  990. IoMarkIrpPending(Irp);
  991. cdData = (PCDROM_DATA)(fdoExtension->CommonExtension.DriverData);
  992. use6Byte = TEST_FLAG(cdData->XAFlags, XA_USE_6_BYTE);
  993. //
  994. // if this test is true, then we will exit the routine within this
  995. // code block, queueing the irp for later completion.
  996. //
  997. if ((cdData->Mmc.IsMmc) &&
  998. (cdData->Mmc.UpdateState != CdromMmcUpdateComplete)
  999. ) {
  1000. ULONG queueDepth;
  1001. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  1002. "CdRomStartIo: [%p] Device needs to update capabilities\n",
  1003. Irp));
  1004. ASSERT(cdData->Mmc.IsMmc);
  1005. ASSERT(cdData->Mmc.CapabilitiesIrp != NULL);
  1006. ASSERT(cdData->Mmc.CapabilitiesIrp != Irp);
  1007. //
  1008. // NOTE - REF #0002
  1009. //
  1010. // the state was either UpdateRequired (which means we will
  1011. // have to start the work item) or UpdateStarted (which means
  1012. // we have already started the work item at least once -- may
  1013. // transparently change to UpdateComplete).
  1014. //
  1015. // if it's update required, we just queue it, change to UpdateStarted,
  1016. // start the workitem, and start the next packet.
  1017. //
  1018. // else, we must queue the item and check the queue depth. if the
  1019. // queue depth is equal to 1, that means the worker item from the
  1020. // previous attempt has already de-queued the items, so we should
  1021. // call this routine again (retry) as an optimization rather than
  1022. // re-add it this irp to the queue. since this is tail recursion,
  1023. // it won't take much/any stack to do this.
  1024. //
  1025. // NOTE: This presumes the following items are true:
  1026. //
  1027. // we only add to the list from CdRomStartIo(), which is serialized.
  1028. // we only set to UpdateStarted from CdRomStartIo(), and only if
  1029. // the state was UpdateRequired.
  1030. // we only set to UpdateRequired from CdRomMmcErrorHandler(), and
  1031. // only if the state was UpdateComplete.
  1032. // we only set to UpdateComplete from the workitem, and assert the
  1033. // state was UpdateStarted.
  1034. // we flush the entire queue in one atomic operation in the workitem,
  1035. // except in the special case described above when we dequeue
  1036. // the request immediately.
  1037. //
  1038. // order of operations is vitally important: queue, then test the depth
  1039. // this will prevent lost irps.
  1040. //
  1041. KeAcquireSpinLock(&cdData->Mmc.DelayedIrpsLock, &oldIrql);
  1042. InsertTailList(&cdData->Mmc.DelayedIrpsList, &Irp->Tail.Overlay.ListEntry);
  1043. queueDepth = ++cdData->Mmc.NumDelayedIrps;
  1044. KeReleaseSpinLock(&cdData->Mmc.DelayedIrpsLock, oldIrql);
  1045. if (queueDepth == 1) {
  1046. if (cdData->Mmc.UpdateState == CdromMmcUpdateRequired) {
  1047. LONG oldState;
  1048. //
  1049. // should free any old partition list info that
  1050. // we've previously saved away and then start the WorkItem
  1051. //
  1052. oldState = InterlockedExchange(&cdData->Mmc.UpdateState,
  1053. CdromMmcUpdateStarted);
  1054. ASSERT(oldState == CdromMmcUpdateRequired);
  1055. IoQueueWorkItem(cdData->Mmc.CapabilitiesWorkItem,
  1056. CdRomUpdateMmcDriveCapabilities,
  1057. DelayedWorkQueue,
  1058. NULL);
  1059. } else {
  1060. //
  1061. // they *just* finished updating, so we should flush the list
  1062. // back onto the StartIo queue and start the next packet.
  1063. //
  1064. CdRompFlushDelayedList(Fdo, &(cdData->Mmc), STATUS_SUCCESS, FALSE);
  1065. }
  1066. }
  1067. //
  1068. // start the next packet so we don't deadlock....
  1069. //
  1070. IoStartNextPacket(Fdo, FALSE);
  1071. return;
  1072. }
  1073. //
  1074. // If the flag is set in the device object
  1075. // force a verify for READ, WRITE and RAW_READ requests
  1076. // Note that ioctls are passed through....
  1077. //
  1078. if (TEST_FLAG(Fdo->Flags, DO_VERIFY_VOLUME) &&
  1079. IS_READ_WRITE_REQUEST(currentIrpStack)) {
  1080. TraceLog((CdromDebugTrace,
  1081. "CdRomStartIo: [%p] Volume needs verified\n", Irp));
  1082. if (!(currentIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME)) {
  1083. if (Irp->Tail.Overlay.Thread) {
  1084. IoSetHardErrorOrVerifyDevice(Irp, Fdo);
  1085. }
  1086. Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
  1087. TraceLog((CdromDebugTrace,
  1088. "CdRomStartIo: [%p] Calling UpdateCapcity - "
  1089. "ioctl event = %p\n",
  1090. Irp,
  1091. nextIrpStack->Parameters.Others.Argument1
  1092. ));
  1093. //
  1094. // our device control dispatch routine stores an event in the next
  1095. // stack location to signal when startio has completed. We need to
  1096. // pass this in so that the update capacity completion routine can
  1097. // set it rather than completing the Irp.
  1098. //
  1099. status = CdRomUpdateCapacity(fdoExtension,
  1100. Irp,
  1101. nextIrpStack->Parameters.Others.Argument1
  1102. );
  1103. TraceLog((CdromDebugTrace,
  1104. "CdRomStartIo: [%p] UpdateCapacity returned %lx\n",
  1105. Irp, status));
  1106. return;
  1107. }
  1108. }
  1109. //
  1110. // fail writes if they are not allowed...
  1111. //
  1112. if ((currentIrpStack->MajorFunction == IRP_MJ_WRITE) &&
  1113. !(cdData->Mmc.WriteAllowed)) {
  1114. TraceLog((CdromDebugError,
  1115. "CdRomStartIo: [%p] Device %p failing write request\n",
  1116. Irp, Fdo));
  1117. Irp->IoStatus.Information = 0;
  1118. Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  1119. BAIL_OUT(Irp);
  1120. CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
  1121. return;
  1122. }
  1123. if (currentIrpStack->MajorFunction == IRP_MJ_READ ||
  1124. currentIrpStack->MajorFunction == IRP_MJ_WRITE ) {
  1125. ULONG maximumTransferLength = fdoExtension->AdapterDescriptor->MaximumTransferLength;
  1126. //
  1127. // Add partition byte offset to make starting byte relative to
  1128. // beginning of disk.
  1129. //
  1130. currentIrpStack->Parameters.Read.ByteOffset.QuadPart +=
  1131. (fdoExtension->CommonExtension.StartingOffset.QuadPart);
  1132. //
  1133. // Calculate number of pages in this transfer.
  1134. //
  1135. transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress),
  1136. currentIrpStack->Parameters.Read.Length);
  1137. //
  1138. // Check if request length is greater than the maximum number of
  1139. // bytes that the hardware can transfer.
  1140. //
  1141. if (cdData->RawAccess) {
  1142. //
  1143. // a writable device must be MMC compliant, which supports
  1144. // READ_CD commands.
  1145. //
  1146. ASSERT(currentIrpStack->MajorFunction != IRP_MJ_WRITE);
  1147. ASSERT(!TEST_FLAG(cdData->XAFlags, XA_USE_READ_CD));
  1148. //
  1149. // Fire off a mode select to switch back to cooked sectors.
  1150. //
  1151. irp2 = IoAllocateIrp((CCHAR)(Fdo->StackSize+1), FALSE);
  1152. if (!irp2) {
  1153. Irp->IoStatus.Information = 0;
  1154. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  1155. BAIL_OUT(Irp);
  1156. CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
  1157. return;
  1158. }
  1159. srb = ExAllocatePoolWithTag(NonPagedPool,
  1160. sizeof(SCSI_REQUEST_BLOCK),
  1161. CDROM_TAG_SRB);
  1162. if (!srb) {
  1163. IoFreeIrp(irp2);
  1164. Irp->IoStatus.Information = 0;
  1165. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  1166. BAIL_OUT(Irp);
  1167. CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
  1168. return;
  1169. }
  1170. RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
  1171. cdb = (PCDB)srb->Cdb;
  1172. //
  1173. // Allocate sense buffer.
  1174. //
  1175. senseBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  1176. SENSE_BUFFER_SIZE,
  1177. CDROM_TAG_SENSE_INFO);
  1178. if (!senseBuffer) {
  1179. ExFreePool(srb);
  1180. IoFreeIrp(irp2);
  1181. Irp->IoStatus.Information = 0;
  1182. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  1183. BAIL_OUT(Irp);
  1184. CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
  1185. return;
  1186. }
  1187. //
  1188. // Set up the irp.
  1189. //
  1190. IoSetNextIrpStackLocation(irp2);
  1191. irp2->IoStatus.Status = STATUS_SUCCESS;
  1192. irp2->IoStatus.Information = 0;
  1193. irp2->Flags = 0;
  1194. irp2->UserBuffer = NULL;
  1195. //
  1196. // Save the device object and irp in a private stack location.
  1197. //
  1198. irpStack = IoGetCurrentIrpStackLocation(irp2);
  1199. irpStack->DeviceObject = Fdo;
  1200. irpStack->Parameters.Others.Argument2 = (PVOID) Irp;
  1201. //
  1202. // The retry count will be in the real Irp, as the retry logic will
  1203. // recreate our private irp.
  1204. //
  1205. if (!(nextIrpStack->Parameters.Others.Argument1)) {
  1206. //
  1207. // Only jam this in if it doesn't exist. The completion routines can
  1208. // call StartIo directly in the case of retries and resetting it will
  1209. // cause infinite loops.
  1210. //
  1211. nextIrpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
  1212. }
  1213. //
  1214. // Construct the IRP stack for the lower level driver.
  1215. //
  1216. irpStack = IoGetNextIrpStackLocation(irp2);
  1217. irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  1218. irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
  1219. irpStack->Parameters.Scsi.Srb = srb;
  1220. srb->Length = SCSI_REQUEST_BLOCK_SIZE;
  1221. srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
  1222. srb->SrbStatus = srb->ScsiStatus = 0;
  1223. srb->NextSrb = 0;
  1224. srb->OriginalRequest = irp2;
  1225. srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
  1226. srb->SenseInfoBuffer = senseBuffer;
  1227. transferByteCount = (use6Byte) ? sizeof(ERROR_RECOVERY_DATA) : sizeof(ERROR_RECOVERY_DATA10);
  1228. dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  1229. transferByteCount,
  1230. CDROM_TAG_RAW);
  1231. if (!dataBuffer) {
  1232. ExFreePool(senseBuffer);
  1233. ExFreePool(srb);
  1234. IoFreeIrp(irp2);
  1235. Irp->IoStatus.Information = 0;
  1236. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  1237. BAIL_OUT(Irp);
  1238. CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
  1239. return;
  1240. }
  1241. irp2->MdlAddress = IoAllocateMdl(dataBuffer,
  1242. transferByteCount,
  1243. FALSE,
  1244. FALSE,
  1245. (PIRP) NULL);
  1246. if (!irp2->MdlAddress) {
  1247. ExFreePool(senseBuffer);
  1248. ExFreePool(srb);
  1249. ExFreePool(dataBuffer);
  1250. IoFreeIrp(irp2);
  1251. Irp->IoStatus.Information = 0;
  1252. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  1253. BAIL_OUT(Irp);
  1254. CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
  1255. return;
  1256. }
  1257. //
  1258. // Prepare the MDL
  1259. //
  1260. MmBuildMdlForNonPagedPool(irp2->MdlAddress);
  1261. srb->DataBuffer = dataBuffer;
  1262. //
  1263. // Set the new block size in the descriptor.
  1264. //
  1265. if (use6Byte) {
  1266. cdData->BlockDescriptor.BlockLength[0] = (UCHAR)(COOKED_SECTOR_SIZE >> 16) & 0xFF;
  1267. cdData->BlockDescriptor.BlockLength[1] = (UCHAR)(COOKED_SECTOR_SIZE >> 8) & 0xFF;
  1268. cdData->BlockDescriptor.BlockLength[2] = (UCHAR)(COOKED_SECTOR_SIZE & 0xFF);
  1269. } else {
  1270. cdData->BlockDescriptor10.BlockLength[0] = (UCHAR)(COOKED_SECTOR_SIZE >> 16) & 0xFF;
  1271. cdData->BlockDescriptor10.BlockLength[1] = (UCHAR)(COOKED_SECTOR_SIZE >> 8) & 0xFF;
  1272. cdData->BlockDescriptor10.BlockLength[2] = (UCHAR)(COOKED_SECTOR_SIZE & 0xFF);
  1273. }
  1274. //
  1275. // Move error page into dataBuffer.
  1276. //
  1277. RtlCopyMemory(srb->DataBuffer, &cdData->Header, transferByteCount);
  1278. //
  1279. // Build and send a mode select to switch into raw mode.
  1280. //
  1281. srb->SrbFlags = fdoExtension->SrbFlags;
  1282. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
  1283. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_OUT);
  1284. srb->DataTransferLength = transferByteCount;
  1285. srb->TimeOutValue = fdoExtension->TimeOutValue * 2;
  1286. if (use6Byte) {
  1287. srb->CdbLength = 6;
  1288. cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
  1289. cdb->MODE_SELECT.PFBit = 1;
  1290. cdb->MODE_SELECT.ParameterListLength = (UCHAR)transferByteCount;
  1291. } else {
  1292. srb->CdbLength = 10;
  1293. cdb->MODE_SELECT10.OperationCode = SCSIOP_MODE_SELECT10;
  1294. cdb->MODE_SELECT10.PFBit = 1;
  1295. cdb->MODE_SELECT10.ParameterListLength[0] = (UCHAR)(transferByteCount >> 8);
  1296. cdb->MODE_SELECT10.ParameterListLength[1] = (UCHAR)(transferByteCount & 0xFF);
  1297. }
  1298. //
  1299. // Update completion routine.
  1300. //
  1301. IoSetCompletionRoutine(irp2,
  1302. CdRomSwitchModeCompletion,
  1303. srb,
  1304. TRUE,
  1305. TRUE,
  1306. TRUE);
  1307. IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
  1308. return;
  1309. }
  1310. //
  1311. // Request needs to be split. Completion of each portion of the
  1312. // request will fire off the next portion. The final request will
  1313. // signal Io to send a new request.
  1314. //
  1315. transferPages =
  1316. fdoExtension->AdapterDescriptor->MaximumPhysicalPages - 1;
  1317. if(maximumTransferLength > (transferPages << PAGE_SHIFT)) {
  1318. maximumTransferLength = transferPages << PAGE_SHIFT;
  1319. }
  1320. //
  1321. // Check that the maximum transfer size is not zero
  1322. //
  1323. if(maximumTransferLength == 0) {
  1324. maximumTransferLength = PAGE_SIZE;
  1325. }
  1326. ClassSplitRequest(Fdo, Irp, maximumTransferLength);
  1327. return;
  1328. } else if (currentIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
  1329. //
  1330. // Allocate an irp, srb and associated structures.
  1331. //
  1332. irp2 = IoAllocateIrp((CCHAR)(Fdo->StackSize+1),
  1333. FALSE);
  1334. if (!irp2) {
  1335. Irp->IoStatus.Information = 0;
  1336. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  1337. BAIL_OUT(Irp);
  1338. CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
  1339. return;
  1340. }
  1341. srb = ExAllocatePoolWithTag(NonPagedPool,
  1342. sizeof(SCSI_REQUEST_BLOCK),
  1343. CDROM_TAG_SRB);
  1344. if (!srb) {
  1345. IoFreeIrp(irp2);
  1346. Irp->IoStatus.Information = 0;
  1347. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  1348. BAIL_OUT(Irp);
  1349. CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
  1350. return;
  1351. }
  1352. RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
  1353. cdb = (PCDB)srb->Cdb;
  1354. //
  1355. // Allocate sense buffer.
  1356. //
  1357. senseBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  1358. SENSE_BUFFER_SIZE,
  1359. CDROM_TAG_SENSE_INFO);
  1360. if (!senseBuffer) {
  1361. ExFreePool(srb);
  1362. IoFreeIrp(irp2);
  1363. Irp->IoStatus.Information = 0;
  1364. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  1365. BAIL_OUT(Irp);
  1366. CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
  1367. return;
  1368. }
  1369. RtlZeroMemory(senseBuffer, SENSE_BUFFER_SIZE);
  1370. //
  1371. // Set up the irp.
  1372. //
  1373. IoSetNextIrpStackLocation(irp2);
  1374. irp2->IoStatus.Status = STATUS_SUCCESS;
  1375. irp2->IoStatus.Information = 0;
  1376. irp2->Flags = 0;
  1377. irp2->UserBuffer = NULL;
  1378. //
  1379. // Save the device object and irp in a private stack location.
  1380. //
  1381. irpStack = IoGetCurrentIrpStackLocation(irp2);
  1382. irpStack->DeviceObject = Fdo;
  1383. irpStack->Parameters.Others.Argument2 = (PVOID) Irp;
  1384. //
  1385. // The retry count will be in the real Irp, as the retry logic will
  1386. // recreate our private irp.
  1387. //
  1388. if (!(nextIrpStack->Parameters.Others.Argument1)) {
  1389. //
  1390. // Only jam this in if it doesn't exist. The completion routines can
  1391. // call StartIo directly in the case of retries and resetting it will
  1392. // cause infinite loops.
  1393. //
  1394. nextIrpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
  1395. }
  1396. //
  1397. // keep track of the new irp as Argument3
  1398. //
  1399. nextIrpStack->Parameters.Others.Argument3 = irp2;
  1400. //
  1401. // Construct the IRP stack for the lower level driver.
  1402. //
  1403. irpStack = IoGetNextIrpStackLocation(irp2);
  1404. irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  1405. irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
  1406. irpStack->Parameters.Scsi.Srb = srb;
  1407. IoSetCompletionRoutine(irp2,
  1408. CdRomDeviceControlCompletion,
  1409. srb,
  1410. TRUE,
  1411. TRUE,
  1412. TRUE);
  1413. //
  1414. // Setup those fields that are generic to all requests.
  1415. //
  1416. srb->Length = SCSI_REQUEST_BLOCK_SIZE;
  1417. srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
  1418. srb->SrbStatus = srb->ScsiStatus = 0;
  1419. srb->NextSrb = 0;
  1420. srb->OriginalRequest = irp2;
  1421. srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
  1422. srb->SenseInfoBuffer = senseBuffer;
  1423. switch (currentIrpStack->Parameters.DeviceIoControl.IoControlCode) {
  1424. case IOCTL_CDROM_RAW_READ: {
  1425. //
  1426. // Determine whether the drive is currently in raw or cooked mode,
  1427. // and which command to use to read the data.
  1428. //
  1429. if (!TEST_FLAG(cdData->XAFlags, XA_USE_READ_CD)) {
  1430. PRAW_READ_INFO rawReadInfo =
  1431. (PRAW_READ_INFO)currentIrpStack->Parameters.DeviceIoControl.Type3InputBuffer;
  1432. ULONG maximumTransferLength;
  1433. ULONG transferPages;
  1434. if (cdData->RawAccess) {
  1435. ULONG startingSector;
  1436. UCHAR min, sec, frame;
  1437. //
  1438. // Free the recently allocated irp, as we don't need it.
  1439. //
  1440. IoFreeIrp(irp2);
  1441. cdb = (PCDB)srb->Cdb;
  1442. RtlZeroMemory(cdb, CDB12GENERIC_LENGTH);
  1443. //
  1444. // Calculate starting offset.
  1445. //
  1446. startingSector = (ULONG)(rawReadInfo->DiskOffset.QuadPart >> fdoExtension->SectorShift);
  1447. transferByteCount = rawReadInfo->SectorCount * RAW_SECTOR_SIZE;
  1448. maximumTransferLength = fdoExtension->AdapterDescriptor->MaximumTransferLength;
  1449. transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress),
  1450. transferByteCount);
  1451. //
  1452. // Determine if request is within limits imposed by miniport.
  1453. //
  1454. if (transferByteCount > maximumTransferLength ||
  1455. transferPages > fdoExtension->AdapterDescriptor->MaximumPhysicalPages) {
  1456. //
  1457. // The claim is that this won't happen, and is backed up by
  1458. // ActiveMovie usage, which does unbuffered XA reads of 0x18000, yet
  1459. // we get only 4 sector requests.
  1460. //
  1461. ExFreePool(senseBuffer);
  1462. ExFreePool(srb);
  1463. Irp->IoStatus.Information = 0;
  1464. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  1465. BAIL_OUT(Irp);
  1466. CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
  1467. return;
  1468. }
  1469. srb->OriginalRequest = Irp;
  1470. srb->SrbFlags = fdoExtension->SrbFlags;
  1471. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
  1472. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
  1473. srb->DataTransferLength = transferByteCount;
  1474. srb->TimeOutValue = fdoExtension->TimeOutValue;
  1475. srb->CdbLength = 10;
  1476. srb->DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
  1477. if (rawReadInfo->TrackMode == CDDA) {
  1478. if (TEST_FLAG(cdData->XAFlags, XA_PLEXTOR_CDDA)) {
  1479. srb->CdbLength = 12;
  1480. cdb->PLXTR_READ_CDDA.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
  1481. cdb->PLXTR_READ_CDDA.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
  1482. cdb->PLXTR_READ_CDDA.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
  1483. cdb->PLXTR_READ_CDDA.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
  1484. cdb->PLXTR_READ_CDDA.TransferBlockByte3 = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
  1485. cdb->PLXTR_READ_CDDA.TransferBlockByte2 = (UCHAR) (rawReadInfo->SectorCount >> 8);
  1486. cdb->PLXTR_READ_CDDA.TransferBlockByte1 = 0;
  1487. cdb->PLXTR_READ_CDDA.TransferBlockByte0 = 0;
  1488. cdb->PLXTR_READ_CDDA.SubCode = 0;
  1489. cdb->PLXTR_READ_CDDA.OperationCode = 0xD8;
  1490. } else if (TEST_FLAG(cdData->XAFlags, XA_NEC_CDDA)) {
  1491. cdb->NEC_READ_CDDA.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
  1492. cdb->NEC_READ_CDDA.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
  1493. cdb->NEC_READ_CDDA.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
  1494. cdb->NEC_READ_CDDA.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
  1495. cdb->NEC_READ_CDDA.TransferBlockByte1 = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
  1496. cdb->NEC_READ_CDDA.TransferBlockByte0 = (UCHAR) (rawReadInfo->SectorCount >> 8);
  1497. cdb->NEC_READ_CDDA.OperationCode = 0xD4;
  1498. }
  1499. } else {
  1500. cdb->CDB10.TransferBlocksMsb = (UCHAR) (rawReadInfo->SectorCount >> 8);
  1501. cdb->CDB10.TransferBlocksLsb = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
  1502. cdb->CDB10.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
  1503. cdb->CDB10.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
  1504. cdb->CDB10.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
  1505. cdb->CDB10.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
  1506. cdb->CDB10.OperationCode = SCSIOP_READ;
  1507. }
  1508. srb->SrbStatus = srb->ScsiStatus = 0;
  1509. nextIrpStack->MajorFunction = IRP_MJ_SCSI;
  1510. nextIrpStack->Parameters.Scsi.Srb = srb;
  1511. // HACKHACK - REF #0001
  1512. //
  1513. // Set up IoCompletion routine address.
  1514. //
  1515. IoSetCompletionRoutine(Irp,
  1516. CdRomXACompletion,
  1517. srb,
  1518. TRUE,
  1519. TRUE,
  1520. TRUE);
  1521. IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, Irp);
  1522. return;
  1523. } else {
  1524. transferByteCount = (use6Byte) ? sizeof(ERROR_RECOVERY_DATA) : sizeof(ERROR_RECOVERY_DATA10);
  1525. dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  1526. transferByteCount,
  1527. CDROM_TAG_RAW );
  1528. if (!dataBuffer) {
  1529. ExFreePool(senseBuffer);
  1530. ExFreePool(srb);
  1531. IoFreeIrp(irp2);
  1532. Irp->IoStatus.Information = 0;
  1533. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  1534. BAIL_OUT(Irp);
  1535. CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
  1536. return;
  1537. }
  1538. irp2->MdlAddress = IoAllocateMdl(dataBuffer,
  1539. transferByteCount,
  1540. FALSE,
  1541. FALSE,
  1542. (PIRP) NULL);
  1543. if (!irp2->MdlAddress) {
  1544. ExFreePool(senseBuffer);
  1545. ExFreePool(srb);
  1546. ExFreePool(dataBuffer);
  1547. IoFreeIrp(irp2);
  1548. Irp->IoStatus.Information = 0;
  1549. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  1550. BAIL_OUT(Irp);
  1551. CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
  1552. return;
  1553. }
  1554. //
  1555. // Prepare the MDL
  1556. //
  1557. MmBuildMdlForNonPagedPool(irp2->MdlAddress);
  1558. srb->DataBuffer = dataBuffer;
  1559. //
  1560. // Set the new block size in the descriptor.
  1561. // This will set the block read size to RAW_SECTOR_SIZE
  1562. // TODO: Set density code, based on operation
  1563. //
  1564. if (use6Byte) {
  1565. cdData->BlockDescriptor.BlockLength[0] = (UCHAR)(RAW_SECTOR_SIZE >> 16) & 0xFF;
  1566. cdData->BlockDescriptor.BlockLength[1] = (UCHAR)(RAW_SECTOR_SIZE >> 8) & 0xFF;
  1567. cdData->BlockDescriptor.BlockLength[2] = (UCHAR)(RAW_SECTOR_SIZE & 0xFF);
  1568. cdData->BlockDescriptor.DensityCode = 0;
  1569. } else {
  1570. cdData->BlockDescriptor10.BlockLength[0] = (UCHAR)(RAW_SECTOR_SIZE >> 16) & 0xFF;
  1571. cdData->BlockDescriptor10.BlockLength[1] = (UCHAR)(RAW_SECTOR_SIZE >> 8) & 0xFF;
  1572. cdData->BlockDescriptor10.BlockLength[2] = (UCHAR)(RAW_SECTOR_SIZE & 0xFF);
  1573. cdData->BlockDescriptor10.DensityCode = 0;
  1574. }
  1575. //
  1576. // Move error page into dataBuffer.
  1577. //
  1578. RtlCopyMemory(srb->DataBuffer, &cdData->Header, transferByteCount);
  1579. //
  1580. // Build and send a mode select to switch into raw mode.
  1581. //
  1582. srb->SrbFlags = fdoExtension->SrbFlags;
  1583. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
  1584. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_OUT);
  1585. srb->DataTransferLength = transferByteCount;
  1586. srb->TimeOutValue = fdoExtension->TimeOutValue * 2;
  1587. if (use6Byte) {
  1588. srb->CdbLength = 6;
  1589. cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
  1590. cdb->MODE_SELECT.PFBit = 1;
  1591. cdb->MODE_SELECT.ParameterListLength = (UCHAR)transferByteCount;
  1592. } else {
  1593. srb->CdbLength = 10;
  1594. cdb->MODE_SELECT10.OperationCode = SCSIOP_MODE_SELECT10;
  1595. cdb->MODE_SELECT10.PFBit = 1;
  1596. cdb->MODE_SELECT10.ParameterListLength[0] = (UCHAR)(transferByteCount >> 8);
  1597. cdb->MODE_SELECT10.ParameterListLength[1] = (UCHAR)(transferByteCount & 0xFF);
  1598. }
  1599. //
  1600. // Update completion routine.
  1601. //
  1602. IoSetCompletionRoutine(irp2,
  1603. CdRomSwitchModeCompletion,
  1604. srb,
  1605. TRUE,
  1606. TRUE,
  1607. TRUE);
  1608. }
  1609. } else {
  1610. PRAW_READ_INFO rawReadInfo =
  1611. (PRAW_READ_INFO)currentIrpStack->Parameters.DeviceIoControl.Type3InputBuffer;
  1612. ULONG startingSector;
  1613. //
  1614. // Free the recently allocated irp, as we don't need it.
  1615. //
  1616. IoFreeIrp(irp2);
  1617. cdb = (PCDB)srb->Cdb;
  1618. RtlZeroMemory(cdb, CDB12GENERIC_LENGTH);
  1619. //
  1620. // Calculate starting offset.
  1621. //
  1622. startingSector = (ULONG)(rawReadInfo->DiskOffset.QuadPart >> fdoExtension->SectorShift);
  1623. transferByteCount = rawReadInfo->SectorCount * RAW_SECTOR_SIZE;
  1624. srb->OriginalRequest = Irp;
  1625. srb->SrbFlags = fdoExtension->SrbFlags;
  1626. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
  1627. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
  1628. srb->DataTransferLength = transferByteCount;
  1629. srb->TimeOutValue = fdoExtension->TimeOutValue;
  1630. srb->DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
  1631. srb->CdbLength = 12;
  1632. srb->SrbStatus = srb->ScsiStatus = 0;
  1633. //
  1634. // Fill in CDB fields.
  1635. //
  1636. cdb = (PCDB)srb->Cdb;
  1637. cdb->READ_CD.TransferBlocks[2] = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
  1638. cdb->READ_CD.TransferBlocks[1] = (UCHAR) (rawReadInfo->SectorCount >> 8 );
  1639. cdb->READ_CD.TransferBlocks[0] = (UCHAR) (rawReadInfo->SectorCount >> 16);
  1640. cdb->READ_CD.StartingLBA[3] = (UCHAR) (startingSector & 0xFF);
  1641. cdb->READ_CD.StartingLBA[2] = (UCHAR) ((startingSector >> 8));
  1642. cdb->READ_CD.StartingLBA[1] = (UCHAR) ((startingSector >> 16));
  1643. cdb->READ_CD.StartingLBA[0] = (UCHAR) ((startingSector >> 24));
  1644. //
  1645. // Setup cdb depending upon the sector type we want.
  1646. //
  1647. switch (rawReadInfo->TrackMode) {
  1648. case CDDA:
  1649. cdb->READ_CD.ExpectedSectorType = CD_DA_SECTOR;
  1650. cdb->READ_CD.IncludeUserData = 1;
  1651. cdb->READ_CD.HeaderCode = 3;
  1652. cdb->READ_CD.IncludeSyncData = 1;
  1653. break;
  1654. case YellowMode2:
  1655. cdb->READ_CD.ExpectedSectorType = YELLOW_MODE2_SECTOR;
  1656. cdb->READ_CD.IncludeUserData = 1;
  1657. cdb->READ_CD.HeaderCode = 1;
  1658. cdb->READ_CD.IncludeSyncData = 1;
  1659. break;
  1660. case XAForm2:
  1661. cdb->READ_CD.ExpectedSectorType = FORM2_MODE2_SECTOR;
  1662. cdb->READ_CD.IncludeUserData = 1;
  1663. cdb->READ_CD.HeaderCode = 3;
  1664. cdb->READ_CD.IncludeSyncData = 1;
  1665. break;
  1666. default:
  1667. ExFreePool(senseBuffer);
  1668. ExFreePool(srb);
  1669. Irp->IoStatus.Information = 0;
  1670. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  1671. BAIL_OUT(Irp);
  1672. CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
  1673. return;
  1674. }
  1675. cdb->READ_CD.OperationCode = SCSIOP_READ_CD;
  1676. nextIrpStack->MajorFunction = IRP_MJ_SCSI;
  1677. nextIrpStack->Parameters.Scsi.Srb = srb;
  1678. // HACKHACK - REF #0001
  1679. //
  1680. // Set up IoCompletion routine address.
  1681. //
  1682. IoSetCompletionRoutine(Irp,
  1683. CdRomXACompletion,
  1684. srb,
  1685. TRUE,
  1686. TRUE,
  1687. TRUE);
  1688. IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, Irp);
  1689. return;
  1690. }
  1691. IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
  1692. return;
  1693. }
  1694. //
  1695. // the _EX version does the same thing on the front end
  1696. //
  1697. case IOCTL_DISK_GET_LENGTH_INFO:
  1698. case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX:
  1699. case IOCTL_DISK_GET_DRIVE_GEOMETRY:
  1700. case IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX:
  1701. case IOCTL_CDROM_GET_DRIVE_GEOMETRY: {
  1702. //
  1703. // Issue ReadCapacity to update device extension
  1704. // with information for current media.
  1705. //
  1706. TraceLog((CdromDebugError,
  1707. "CdRomStartIo: Get drive geometry/length "
  1708. "info (%p)\n", Irp));
  1709. //
  1710. // setup remaining srb and cdb parameters.
  1711. //
  1712. srb->SrbFlags = fdoExtension->SrbFlags;
  1713. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
  1714. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
  1715. srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
  1716. srb->CdbLength = 10;
  1717. srb->TimeOutValue = fdoExtension->TimeOutValue;
  1718. dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  1719. sizeof(READ_CAPACITY_DATA),
  1720. CDROM_TAG_READ_CAP);
  1721. if (!dataBuffer) {
  1722. ExFreePool(senseBuffer);
  1723. ExFreePool(srb);
  1724. IoFreeIrp(irp2);
  1725. Irp->IoStatus.Information = 0;
  1726. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  1727. BAIL_OUT(Irp);
  1728. CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
  1729. return;
  1730. }
  1731. irp2->MdlAddress = IoAllocateMdl(dataBuffer,
  1732. sizeof(READ_CAPACITY_DATA),
  1733. FALSE,
  1734. FALSE,
  1735. (PIRP) NULL);
  1736. if (!irp2->MdlAddress) {
  1737. ExFreePool(senseBuffer);
  1738. ExFreePool(srb);
  1739. ExFreePool(dataBuffer);
  1740. IoFreeIrp(irp2);
  1741. Irp->IoStatus.Information = 0;
  1742. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  1743. BAIL_OUT(Irp);
  1744. CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
  1745. return;
  1746. }
  1747. //
  1748. // Prepare the MDL
  1749. //
  1750. MmBuildMdlForNonPagedPool(irp2->MdlAddress);
  1751. srb->DataBuffer = dataBuffer;
  1752. cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
  1753. IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
  1754. return;
  1755. }
  1756. case IOCTL_CDROM_GET_CONFIGURATION: {
  1757. PGET_CONFIGURATION_IOCTL_INPUT inputBuffer;
  1758. TraceLog((CdromDebugError,
  1759. "CdRomStartIo: Get configuration (%p)\n", Irp));
  1760. if (!cdData->Mmc.IsMmc) {
  1761. ExFreePool(senseBuffer);
  1762. ExFreePool(srb);
  1763. IoFreeIrp(irp2);
  1764. Irp->IoStatus.Information = 0;
  1765. Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  1766. BAIL_OUT(Irp);
  1767. CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
  1768. return;
  1769. }
  1770. transferByteCount = currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
  1771. dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  1772. transferByteCount,
  1773. CDROM_TAG_GET_CONFIG);
  1774. if (!dataBuffer) {
  1775. ExFreePool(senseBuffer);
  1776. ExFreePool(srb);
  1777. IoFreeIrp(irp2);
  1778. Irp->IoStatus.Information = 0;
  1779. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  1780. BAIL_OUT(Irp);
  1781. CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
  1782. return;
  1783. }
  1784. irp2->MdlAddress = IoAllocateMdl(dataBuffer,
  1785. transferByteCount,
  1786. FALSE,
  1787. FALSE,
  1788. (PIRP) NULL);
  1789. if (!irp2->MdlAddress) {
  1790. ExFreePool(dataBuffer);
  1791. ExFreePool(senseBuffer);
  1792. ExFreePool(srb);
  1793. IoFreeIrp(irp2);
  1794. Irp->IoStatus.Information = 0;
  1795. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  1796. BAIL_OUT(Irp);
  1797. CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
  1798. return;
  1799. }
  1800. MmBuildMdlForNonPagedPool(irp2->MdlAddress);
  1801. //
  1802. // setup remaining srb and cdb parameters
  1803. //
  1804. srb->SrbFlags = fdoExtension->SrbFlags;
  1805. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
  1806. srb->DataTransferLength = transferByteCount;
  1807. srb->CdbLength = 10;
  1808. srb->TimeOutValue = fdoExtension->TimeOutValue;
  1809. srb->DataBuffer = dataBuffer;
  1810. cdb->GET_CONFIGURATION.OperationCode = SCSIOP_GET_CONFIGURATION;
  1811. cdb->GET_CONFIGURATION.AllocationLength[0] = (UCHAR)(transferByteCount >> 8);
  1812. cdb->GET_CONFIGURATION.AllocationLength[1] = (UCHAR)(transferByteCount & 0xff);
  1813. inputBuffer = (PGET_CONFIGURATION_IOCTL_INPUT)Irp->AssociatedIrp.SystemBuffer;
  1814. cdb->GET_CONFIGURATION.StartingFeature[0] = (UCHAR)(inputBuffer->Feature >> 8);
  1815. cdb->GET_CONFIGURATION.StartingFeature[1] = (UCHAR)(inputBuffer->Feature & 0xff);
  1816. cdb->GET_CONFIGURATION.RequestType = (UCHAR)(inputBuffer->RequestType);
  1817. IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
  1818. return;
  1819. }
  1820. case IOCTL_DISK_VERIFY: {
  1821. PVERIFY_INFORMATION verifyInfo = Irp->AssociatedIrp.SystemBuffer;
  1822. LARGE_INTEGER byteOffset;
  1823. ULONG sectorOffset;
  1824. USHORT sectorCount;
  1825. if (!cdData->Mmc.WriteAllowed) {
  1826. ExFreePool(senseBuffer);
  1827. ExFreePool(srb);
  1828. IoFreeIrp(irp2);
  1829. Irp->IoStatus.Information = 0;
  1830. Irp->IoStatus.Status = STATUS_MEDIA_WRITE_PROTECTED;
  1831. BAIL_OUT(Irp);
  1832. CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
  1833. return;
  1834. }
  1835. //
  1836. // Verify sectors
  1837. //
  1838. srb->CdbLength = 10;
  1839. cdb->CDB10.OperationCode = SCSIOP_VERIFY;
  1840. //
  1841. // Add disk offset to starting sector.
  1842. //
  1843. byteOffset.QuadPart = commonExtension->StartingOffset.QuadPart +
  1844. verifyInfo->StartingOffset.QuadPart;
  1845. //
  1846. // Convert byte offset to sector offset.
  1847. //
  1848. sectorOffset = (ULONG)(byteOffset.QuadPart >> fdoExtension->SectorShift);
  1849. //
  1850. // Convert ULONG byte count to USHORT sector count.
  1851. //
  1852. sectorCount = (USHORT)(verifyInfo->Length >> fdoExtension->SectorShift);
  1853. //
  1854. // Move little endian values into CDB in big endian format.
  1855. //
  1856. cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&sectorOffset)->Byte3;
  1857. cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&sectorOffset)->Byte2;
  1858. cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&sectorOffset)->Byte1;
  1859. cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&sectorOffset)->Byte0;
  1860. cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&sectorCount)->Byte1;
  1861. cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&sectorCount)->Byte0;
  1862. //
  1863. // The verify command is used by the NT FORMAT utility and
  1864. // requests are sent down for 5% of the volume size. The
  1865. // request timeout value is calculated based on the number of
  1866. // sectors verified.
  1867. //
  1868. srb->TimeOutValue = ((sectorCount + 0x7F) >> 7) *
  1869. fdoExtension->TimeOutValue;
  1870. IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
  1871. return;
  1872. }
  1873. case IOCTL_STORAGE_CHECK_VERIFY:
  1874. case IOCTL_DISK_CHECK_VERIFY:
  1875. case IOCTL_CDROM_CHECK_VERIFY: {
  1876. //
  1877. // Since a test unit ready is about to be performed, reset the
  1878. // timer value to decrease the opportunities for it to race with
  1879. // this code.
  1880. //
  1881. ClassResetMediaChangeTimer(fdoExtension);
  1882. //
  1883. // Set up the SRB/CDB
  1884. //
  1885. srb->CdbLength = 6;
  1886. cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
  1887. srb->TimeOutValue = fdoExtension->TimeOutValue * 2;
  1888. srb->SrbFlags = fdoExtension->SrbFlags;
  1889. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
  1890. SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER);
  1891. TraceLog((CdromDebugTrace,
  1892. "CdRomStartIo: [%p] Sending CHECK_VERIFY irp %p\n",
  1893. Irp, irp2));
  1894. IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
  1895. return;
  1896. }
  1897. case IOCTL_DVD_READ_STRUCTURE: {
  1898. CdRomDeviceControlDvdReadStructure(Fdo, Irp, irp2, srb);
  1899. return;
  1900. }
  1901. case IOCTL_DVD_END_SESSION: {
  1902. CdRomDeviceControlDvdEndSession(Fdo, Irp, irp2, srb);
  1903. return;
  1904. }
  1905. case IOCTL_DVD_START_SESSION:
  1906. case IOCTL_DVD_READ_KEY: {
  1907. CdRomDeviceControlDvdStartSessionReadKey(Fdo, Irp, irp2, srb);
  1908. return;
  1909. }
  1910. case IOCTL_DVD_SEND_KEY:
  1911. case IOCTL_DVD_SEND_KEY2: {
  1912. CdRomDeviceControlDvdSendKey (Fdo, Irp, irp2, srb);
  1913. return;
  1914. }
  1915. case IOCTL_CDROM_READ_TOC_EX: {
  1916. PCDROM_READ_TOC_EX inputBuffer = Irp->AssociatedIrp.SystemBuffer;
  1917. transferByteCount = currentIrpStack->Parameters.Read.Length;
  1918. dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  1919. transferByteCount,
  1920. CDROM_TAG_TOC);
  1921. if (!dataBuffer) {
  1922. ExFreePool(senseBuffer);
  1923. ExFreePool(srb);
  1924. IoFreeIrp(irp2);
  1925. Irp->IoStatus.Information = 0;
  1926. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  1927. BAIL_OUT(Irp);
  1928. CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
  1929. return;
  1930. }
  1931. irp2->MdlAddress = IoAllocateMdl(dataBuffer,
  1932. transferByteCount,
  1933. FALSE,
  1934. FALSE,
  1935. (PIRP) NULL);
  1936. if (!irp2->MdlAddress) {
  1937. ExFreePool(senseBuffer);
  1938. ExFreePool(srb);
  1939. ExFreePool(dataBuffer);
  1940. IoFreeIrp(irp2);
  1941. Irp->IoStatus.Information = 0;
  1942. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  1943. BAIL_OUT(Irp);
  1944. CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
  1945. return;
  1946. }
  1947. //
  1948. // setup the request per user request
  1949. // do validity checking in devctl dispatch, not here
  1950. //
  1951. cdb->READ_TOC.OperationCode = SCSIOP_READ_TOC;
  1952. cdb->READ_TOC.Msf = inputBuffer->Msf;
  1953. cdb->READ_TOC.Format2 = inputBuffer->Format;
  1954. cdb->READ_TOC.StartingTrack = inputBuffer->SessionTrack;
  1955. cdb->READ_TOC.AllocationLength[0] = (UCHAR)(transferByteCount >> 8);
  1956. cdb->READ_TOC.AllocationLength[1] = (UCHAR)(transferByteCount & 0xff);
  1957. //
  1958. // Prepare the MDL
  1959. //
  1960. MmBuildMdlForNonPagedPool(irp2->MdlAddress);
  1961. //
  1962. // do the standard stuff....
  1963. //
  1964. srb->SrbFlags = fdoExtension->SrbFlags;
  1965. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
  1966. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
  1967. srb->DataTransferLength = transferByteCount;
  1968. srb->CdbLength = 10;
  1969. srb->TimeOutValue = fdoExtension->TimeOutValue;
  1970. srb->DataBuffer = dataBuffer;
  1971. IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
  1972. return;
  1973. }
  1974. case IOCTL_CDROM_GET_LAST_SESSION:
  1975. case IOCTL_CDROM_READ_TOC: {
  1976. if (currentIrpStack->Parameters.DeviceIoControl.IoControlCode ==
  1977. IOCTL_CDROM_GET_LAST_SESSION) {
  1978. //
  1979. // Set format to return first and last session numbers.
  1980. //
  1981. cdb->READ_TOC.Format = CDROM_READ_TOC_EX_FORMAT_SESSION;
  1982. } else {
  1983. //
  1984. // Use MSF addressing
  1985. //
  1986. cdb->READ_TOC.Msf = 1;
  1987. }
  1988. transferByteCount =
  1989. currentIrpStack->Parameters.Read.Length >
  1990. sizeof(CDROM_TOC) ? sizeof(CDROM_TOC):
  1991. currentIrpStack->Parameters.Read.Length;
  1992. //
  1993. // Set size of TOC structure.
  1994. //
  1995. cdb->READ_TOC.AllocationLength[0] = (UCHAR) (transferByteCount >> 8);
  1996. cdb->READ_TOC.AllocationLength[1] = (UCHAR) (transferByteCount & 0xFF);
  1997. //
  1998. // setup remaining srb and cdb parameters.
  1999. //
  2000. srb->SrbFlags = fdoExtension->SrbFlags;
  2001. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
  2002. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
  2003. srb->DataTransferLength = transferByteCount;
  2004. srb->CdbLength = 10;
  2005. srb->TimeOutValue = fdoExtension->TimeOutValue;
  2006. dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  2007. transferByteCount,
  2008. CDROM_TAG_TOC);
  2009. if (!dataBuffer) {
  2010. ExFreePool(senseBuffer);
  2011. ExFreePool(srb);
  2012. IoFreeIrp(irp2);
  2013. Irp->IoStatus.Information = 0;
  2014. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  2015. BAIL_OUT(Irp);
  2016. CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
  2017. return;
  2018. }
  2019. irp2->MdlAddress = IoAllocateMdl(dataBuffer,
  2020. transferByteCount,
  2021. FALSE,
  2022. FALSE,
  2023. (PIRP) NULL);
  2024. if (!irp2->MdlAddress) {
  2025. ExFreePool(senseBuffer);
  2026. ExFreePool(srb);
  2027. ExFreePool(dataBuffer);
  2028. IoFreeIrp(irp2);
  2029. Irp->IoStatus.Information = 0;
  2030. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  2031. BAIL_OUT(Irp);
  2032. CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
  2033. return;
  2034. }
  2035. //
  2036. // Prepare the MDL
  2037. //
  2038. MmBuildMdlForNonPagedPool(irp2->MdlAddress);
  2039. srb->DataBuffer = dataBuffer;
  2040. cdb->READ_TOC.OperationCode = SCSIOP_READ_TOC;
  2041. IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
  2042. return;
  2043. }
  2044. case IOCTL_CDROM_PLAY_AUDIO_MSF: {
  2045. PCDROM_PLAY_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
  2046. //
  2047. // Set up the SRB/CDB
  2048. //
  2049. srb->CdbLength = 10;
  2050. cdb->PLAY_AUDIO_MSF.OperationCode = SCSIOP_PLAY_AUDIO_MSF;
  2051. cdb->PLAY_AUDIO_MSF.StartingM = inputBuffer->StartingM;
  2052. cdb->PLAY_AUDIO_MSF.StartingS = inputBuffer->StartingS;
  2053. cdb->PLAY_AUDIO_MSF.StartingF = inputBuffer->StartingF;
  2054. cdb->PLAY_AUDIO_MSF.EndingM = inputBuffer->EndingM;
  2055. cdb->PLAY_AUDIO_MSF.EndingS = inputBuffer->EndingS;
  2056. cdb->PLAY_AUDIO_MSF.EndingF = inputBuffer->EndingF;
  2057. srb->TimeOutValue = fdoExtension->TimeOutValue;
  2058. srb->SrbFlags = fdoExtension->SrbFlags;
  2059. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
  2060. SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER);
  2061. IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
  2062. return;
  2063. }
  2064. case IOCTL_CDROM_READ_Q_CHANNEL: {
  2065. PSUB_Q_CHANNEL_DATA userChannelData =
  2066. Irp->AssociatedIrp.SystemBuffer;
  2067. PCDROM_SUB_Q_DATA_FORMAT inputBuffer =
  2068. Irp->AssociatedIrp.SystemBuffer;
  2069. //
  2070. // Allocate buffer for subq channel information.
  2071. //
  2072. dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  2073. sizeof(SUB_Q_CHANNEL_DATA),
  2074. CDROM_TAG_SUB_Q);
  2075. if (!dataBuffer) {
  2076. ExFreePool(senseBuffer);
  2077. ExFreePool(srb);
  2078. IoFreeIrp(irp2);
  2079. Irp->IoStatus.Information = 0;
  2080. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  2081. BAIL_OUT(Irp);
  2082. CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
  2083. return;
  2084. }
  2085. irp2->MdlAddress = IoAllocateMdl(dataBuffer,
  2086. sizeof(SUB_Q_CHANNEL_DATA),
  2087. FALSE,
  2088. FALSE,
  2089. (PIRP) NULL);
  2090. if (!irp2->MdlAddress) {
  2091. ExFreePool(senseBuffer);
  2092. ExFreePool(srb);
  2093. ExFreePool(dataBuffer);
  2094. IoFreeIrp(irp2);
  2095. Irp->IoStatus.Information = 0;
  2096. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  2097. BAIL_OUT(Irp);
  2098. CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
  2099. return;
  2100. }
  2101. //
  2102. // Prepare the MDL
  2103. //
  2104. MmBuildMdlForNonPagedPool(irp2->MdlAddress);
  2105. srb->DataBuffer = dataBuffer;
  2106. //
  2107. // Always logical unit 0, but only use MSF addressing
  2108. // for IOCTL_CDROM_CURRENT_POSITION
  2109. //
  2110. if (inputBuffer->Format==IOCTL_CDROM_CURRENT_POSITION)
  2111. cdb->SUBCHANNEL.Msf = CDB_USE_MSF;
  2112. //
  2113. // Return subchannel data
  2114. //
  2115. cdb->SUBCHANNEL.SubQ = CDB_SUBCHANNEL_BLOCK;
  2116. //
  2117. // Specify format of informatin to return
  2118. //
  2119. cdb->SUBCHANNEL.Format = inputBuffer->Format;
  2120. //
  2121. // Specify which track to access (only used by Track ISRC reads)
  2122. //
  2123. if (inputBuffer->Format==IOCTL_CDROM_TRACK_ISRC) {
  2124. cdb->SUBCHANNEL.TrackNumber = inputBuffer->Track;
  2125. }
  2126. //
  2127. // Set size of channel data -- however, this is dependent on
  2128. // what information we are requesting (which Format)
  2129. //
  2130. switch( inputBuffer->Format ) {
  2131. case IOCTL_CDROM_CURRENT_POSITION:
  2132. transferByteCount = sizeof(SUB_Q_CURRENT_POSITION);
  2133. break;
  2134. case IOCTL_CDROM_MEDIA_CATALOG:
  2135. transferByteCount = sizeof(SUB_Q_MEDIA_CATALOG_NUMBER);
  2136. break;
  2137. case IOCTL_CDROM_TRACK_ISRC:
  2138. transferByteCount = sizeof(SUB_Q_TRACK_ISRC);
  2139. break;
  2140. }
  2141. cdb->SUBCHANNEL.AllocationLength[0] = (UCHAR) (transferByteCount >> 8);
  2142. cdb->SUBCHANNEL.AllocationLength[1] = (UCHAR) (transferByteCount & 0xFF);
  2143. cdb->SUBCHANNEL.OperationCode = SCSIOP_READ_SUB_CHANNEL;
  2144. srb->SrbFlags = fdoExtension->SrbFlags;
  2145. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
  2146. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
  2147. srb->DataTransferLength = transferByteCount;
  2148. srb->CdbLength = 10;
  2149. srb->TimeOutValue = fdoExtension->TimeOutValue;
  2150. IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
  2151. return;
  2152. }
  2153. case IOCTL_CDROM_PAUSE_AUDIO: {
  2154. cdb->PAUSE_RESUME.OperationCode = SCSIOP_PAUSE_RESUME;
  2155. cdb->PAUSE_RESUME.Action = CDB_AUDIO_PAUSE;
  2156. srb->CdbLength = 10;
  2157. srb->TimeOutValue = fdoExtension->TimeOutValue;
  2158. srb->SrbFlags = fdoExtension->SrbFlags;
  2159. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
  2160. SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER);
  2161. IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
  2162. return;
  2163. }
  2164. case IOCTL_CDROM_RESUME_AUDIO: {
  2165. cdb->PAUSE_RESUME.OperationCode = SCSIOP_PAUSE_RESUME;
  2166. cdb->PAUSE_RESUME.Action = CDB_AUDIO_RESUME;
  2167. srb->CdbLength = 10;
  2168. srb->TimeOutValue = fdoExtension->TimeOutValue;
  2169. srb->SrbFlags = fdoExtension->SrbFlags;
  2170. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
  2171. SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER);
  2172. IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
  2173. return;
  2174. }
  2175. case IOCTL_CDROM_SEEK_AUDIO_MSF: {
  2176. PCDROM_SEEK_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
  2177. ULONG logicalBlockAddress;
  2178. logicalBlockAddress = MSF_TO_LBA(inputBuffer->M, inputBuffer->S, inputBuffer->F);
  2179. cdb->SEEK.OperationCode = SCSIOP_SEEK;
  2180. cdb->SEEK.LogicalBlockAddress[0] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte3;
  2181. cdb->SEEK.LogicalBlockAddress[1] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte2;
  2182. cdb->SEEK.LogicalBlockAddress[2] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte1;
  2183. cdb->SEEK.LogicalBlockAddress[3] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte0;
  2184. srb->CdbLength = 10;
  2185. srb->TimeOutValue = fdoExtension->TimeOutValue;
  2186. srb->SrbFlags = fdoExtension->SrbFlags;
  2187. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
  2188. SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER);
  2189. IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
  2190. return;
  2191. }
  2192. case IOCTL_CDROM_STOP_AUDIO: {
  2193. cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
  2194. cdb->START_STOP.Immediate = 1;
  2195. cdb->START_STOP.Start = 0;
  2196. cdb->START_STOP.LoadEject = 0;
  2197. srb->CdbLength = 6;
  2198. srb->TimeOutValue = fdoExtension->TimeOutValue;
  2199. srb->SrbFlags = fdoExtension->SrbFlags;
  2200. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
  2201. SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER);
  2202. IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
  2203. return;
  2204. }
  2205. case IOCTL_CDROM_GET_CONTROL: {
  2206. PAUDIO_OUTPUT audioOutput;
  2207. PCDROM_AUDIO_CONTROL audioControl = Irp->AssociatedIrp.SystemBuffer;
  2208. //
  2209. // Allocate buffer for volume control information.
  2210. //
  2211. dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  2212. MODE_DATA_SIZE,
  2213. CDROM_TAG_VOLUME);
  2214. if (!dataBuffer) {
  2215. ExFreePool(senseBuffer);
  2216. ExFreePool(srb);
  2217. IoFreeIrp(irp2);
  2218. Irp->IoStatus.Information = 0;
  2219. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  2220. BAIL_OUT(Irp);
  2221. CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
  2222. return;
  2223. }
  2224. irp2->MdlAddress = IoAllocateMdl(dataBuffer,
  2225. MODE_DATA_SIZE,
  2226. FALSE,
  2227. FALSE,
  2228. (PIRP) NULL);
  2229. if (!irp2->MdlAddress) {
  2230. ExFreePool(senseBuffer);
  2231. ExFreePool(srb);
  2232. ExFreePool(dataBuffer);
  2233. IoFreeIrp(irp2);
  2234. Irp->IoStatus.Information = 0;
  2235. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  2236. BAIL_OUT(Irp);
  2237. CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
  2238. return;
  2239. }
  2240. //
  2241. // Prepare the MDL
  2242. //
  2243. MmBuildMdlForNonPagedPool(irp2->MdlAddress);
  2244. srb->DataBuffer = dataBuffer;
  2245. RtlZeroMemory(dataBuffer, MODE_DATA_SIZE);
  2246. //
  2247. // Setup for either 6 or 10 byte CDBs.
  2248. //
  2249. if (use6Byte) {
  2250. cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
  2251. cdb->MODE_SENSE.PageCode = CDROM_AUDIO_CONTROL_PAGE;
  2252. cdb->MODE_SENSE.AllocationLength = MODE_DATA_SIZE;
  2253. //
  2254. // Disable block descriptors.
  2255. //
  2256. cdb->MODE_SENSE.Dbd = TRUE;
  2257. srb->CdbLength = 6;
  2258. } else {
  2259. cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
  2260. cdb->MODE_SENSE10.PageCode = CDROM_AUDIO_CONTROL_PAGE;
  2261. cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(MODE_DATA_SIZE >> 8);
  2262. cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(MODE_DATA_SIZE & 0xFF);
  2263. //
  2264. // Disable block descriptors.
  2265. //
  2266. cdb->MODE_SENSE10.Dbd = TRUE;
  2267. srb->CdbLength = 10;
  2268. }
  2269. srb->TimeOutValue = fdoExtension->TimeOutValue;
  2270. srb->DataTransferLength = MODE_DATA_SIZE;
  2271. srb->SrbFlags = fdoExtension->SrbFlags;
  2272. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
  2273. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
  2274. IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
  2275. return;
  2276. }
  2277. case IOCTL_CDROM_GET_VOLUME:
  2278. case IOCTL_CDROM_SET_VOLUME: {
  2279. dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  2280. MODE_DATA_SIZE,
  2281. CDROM_TAG_VOLUME);
  2282. if (!dataBuffer) {
  2283. ExFreePool(senseBuffer);
  2284. ExFreePool(srb);
  2285. IoFreeIrp(irp2);
  2286. Irp->IoStatus.Information = 0;
  2287. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  2288. BAIL_OUT(Irp);
  2289. CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
  2290. return;
  2291. }
  2292. irp2->MdlAddress = IoAllocateMdl(dataBuffer,
  2293. MODE_DATA_SIZE,
  2294. FALSE,
  2295. FALSE,
  2296. (PIRP) NULL);
  2297. if (!irp2->MdlAddress) {
  2298. ExFreePool(senseBuffer);
  2299. ExFreePool(srb);
  2300. ExFreePool(dataBuffer);
  2301. IoFreeIrp(irp2);
  2302. Irp->IoStatus.Information = 0;
  2303. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  2304. BAIL_OUT(Irp);
  2305. CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
  2306. return;
  2307. }
  2308. //
  2309. // Prepare the MDL
  2310. //
  2311. MmBuildMdlForNonPagedPool(irp2->MdlAddress);
  2312. srb->DataBuffer = dataBuffer;
  2313. RtlZeroMemory(dataBuffer, MODE_DATA_SIZE);
  2314. if (use6Byte) {
  2315. cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
  2316. cdb->MODE_SENSE.PageCode = CDROM_AUDIO_CONTROL_PAGE;
  2317. cdb->MODE_SENSE.AllocationLength = MODE_DATA_SIZE;
  2318. srb->CdbLength = 6;
  2319. } else {
  2320. cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
  2321. cdb->MODE_SENSE10.PageCode = CDROM_AUDIO_CONTROL_PAGE;
  2322. cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(MODE_DATA_SIZE >> 8);
  2323. cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(MODE_DATA_SIZE & 0xFF);
  2324. srb->CdbLength = 10;
  2325. }
  2326. srb->TimeOutValue = fdoExtension->TimeOutValue;
  2327. srb->DataTransferLength = MODE_DATA_SIZE;
  2328. srb->SrbFlags = fdoExtension->SrbFlags;
  2329. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
  2330. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
  2331. if (currentIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_SET_VOLUME) {
  2332. //
  2333. // Setup a different completion routine as the mode sense data is needed in order
  2334. // to send the mode select.
  2335. //
  2336. IoSetCompletionRoutine(irp2,
  2337. CdRomSetVolumeIntermediateCompletion,
  2338. srb,
  2339. TRUE,
  2340. TRUE,
  2341. TRUE);
  2342. }
  2343. IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
  2344. return;
  2345. }
  2346. case IOCTL_STORAGE_SET_READ_AHEAD: {
  2347. PSTORAGE_SET_READ_AHEAD readAhead = Irp->AssociatedIrp.SystemBuffer;
  2348. ULONG blockAddress;
  2349. PFOUR_BYTE fourByte = (PFOUR_BYTE) &blockAddress;
  2350. //
  2351. // setup the SRB for a set readahead command
  2352. //
  2353. cdb->SET_READ_AHEAD.OperationCode = SCSIOP_SET_READ_AHEAD;
  2354. blockAddress = (ULONG) (readAhead->TriggerAddress.QuadPart >>
  2355. fdoExtension->SectorShift);
  2356. cdb->SET_READ_AHEAD.TriggerLBA[0] = fourByte->Byte3;
  2357. cdb->SET_READ_AHEAD.TriggerLBA[1] = fourByte->Byte2;
  2358. cdb->SET_READ_AHEAD.TriggerLBA[2] = fourByte->Byte1;
  2359. cdb->SET_READ_AHEAD.TriggerLBA[3] = fourByte->Byte0;
  2360. blockAddress = (ULONG) (readAhead->TargetAddress.QuadPart >>
  2361. fdoExtension->SectorShift);
  2362. cdb->SET_READ_AHEAD.ReadAheadLBA[0] = fourByte->Byte3;
  2363. cdb->SET_READ_AHEAD.ReadAheadLBA[1] = fourByte->Byte2;
  2364. cdb->SET_READ_AHEAD.ReadAheadLBA[2] = fourByte->Byte1;
  2365. cdb->SET_READ_AHEAD.ReadAheadLBA[3] = fourByte->Byte0;
  2366. srb->CdbLength = 12;
  2367. srb->TimeOutValue = fdoExtension->TimeOutValue;
  2368. srb->SrbFlags = fdoExtension->SrbFlags;
  2369. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
  2370. SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER);
  2371. IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
  2372. return;
  2373. }
  2374. case IOCTL_DISK_GET_DRIVE_LAYOUT:
  2375. case IOCTL_DISK_GET_DRIVE_LAYOUT_EX:
  2376. case IOCTL_DISK_GET_PARTITION_INFO:
  2377. case IOCTL_DISK_GET_PARTITION_INFO_EX: {
  2378. ASSERT(irp2);
  2379. ASSERT(senseBuffer);
  2380. ASSERT(srb);
  2381. ExFreePool(srb);
  2382. ExFreePool(senseBuffer);
  2383. IoFreeIrp(irp2);
  2384. //
  2385. // NOTE: should probably update the media's capacity first...
  2386. //
  2387. CdromFakePartitionInfo(commonExtension, Irp);
  2388. return;
  2389. }
  2390. case IOCTL_DISK_IS_WRITABLE: {
  2391. TraceLog((CdromDebugWarning,
  2392. "CdRomStartIo: DiskIsWritable (%p) - returning %s\n",
  2393. Irp, (cdData->Mmc.WriteAllowed ? "TRUE" : "false")));
  2394. ASSERT(irp2);
  2395. ASSERT(senseBuffer);
  2396. ASSERT(srb);
  2397. ExFreePool(srb);
  2398. ExFreePool(senseBuffer);
  2399. IoFreeIrp(irp2);
  2400. Irp->IoStatus.Information = 0;
  2401. if (cdData->Mmc.WriteAllowed) {
  2402. Irp->IoStatus.Status = STATUS_SUCCESS;
  2403. } else {
  2404. Irp->IoStatus.Status = STATUS_MEDIA_WRITE_PROTECTED;
  2405. }
  2406. CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
  2407. return;
  2408. }
  2409. default: {
  2410. UCHAR uniqueAddress;
  2411. //
  2412. // Just complete the request - CdRomClassIoctlCompletion will take
  2413. // care of it for us
  2414. //
  2415. // NOTE: THIS IS A SYNCHRONIZATION METHOD!!!
  2416. //
  2417. //
  2418. // Acquire a new copy of the lock so that ClassCompleteRequest
  2419. // doesn't get confused when we complete the other request while
  2420. // holding the lock.
  2421. //
  2422. //
  2423. // NOTE: CdRomDeviceControlDispatch/CdRomDeviceControlCompletion
  2424. // wait for the event and eventually calls
  2425. // IoStartNextPacket()
  2426. //
  2427. ASSERT(irp2);
  2428. ASSERT(senseBuffer);
  2429. ASSERT(srb);
  2430. ExFreePool(srb);
  2431. ExFreePool(senseBuffer);
  2432. IoFreeIrp(irp2);
  2433. ClassAcquireRemoveLock(Fdo, (PIRP)&uniqueAddress);
  2434. ClassReleaseRemoveLock(Fdo, Irp);
  2435. ClassCompleteRequest(Fdo, Irp, IO_NO_INCREMENT);
  2436. ClassReleaseRemoveLock(Fdo, (PIRP)&uniqueAddress);
  2437. return;
  2438. }
  2439. } // end switch()
  2440. } else if (currentIrpStack->MajorFunction == IRP_MJ_SHUTDOWN ||
  2441. currentIrpStack->MajorFunction == IRP_MJ_FLUSH_BUFFERS) {
  2442. currentIrpStack->Parameters.Others.Argument1 = 0;
  2443. Irp->IoStatus.Status = STATUS_SUCCESS;
  2444. CdRomShutdownFlushCompletion(Fdo, NULL, Irp);
  2445. return;
  2446. }
  2447. //
  2448. // If a read or an unhandled IRP_MJ_XX, end up here. The unhandled IRP_MJ's
  2449. // are expected and composed of AutoRun Irps, at present.
  2450. //
  2451. IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  2452. return;
  2453. }
  2454. NTSTATUS
  2455. CdRomReadWriteVerification(
  2456. IN PDEVICE_OBJECT DeviceObject,
  2457. IN PIRP Irp
  2458. )
  2459. /*++
  2460. Routine Description:
  2461. This is the entry called by the I/O system for read requests.
  2462. It builds the SRB and sends it to the port driver.
  2463. Arguments:
  2464. DeviceObject - the system object for the device.
  2465. Irp - IRP involved.
  2466. Return Value:
  2467. NT Status
  2468. --*/
  2469. {
  2470. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  2471. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  2472. PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
  2473. ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
  2474. LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
  2475. PCDROM_DATA cdData = (PCDROM_DATA)(commonExtension->DriverData);
  2476. SCSI_REQUEST_BLOCK srb;
  2477. PCDB cdb = (PCDB)srb.Cdb;
  2478. NTSTATUS status;
  2479. PAGED_CODE();
  2480. //
  2481. // note: we are no longer failing write commands immediately
  2482. // they are now failed in StartIo based upon media ability
  2483. //
  2484. //
  2485. // If the cd is playing music then reject this request.
  2486. //
  2487. if (PLAY_ACTIVE(fdoExtension)) {
  2488. Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
  2489. return STATUS_DEVICE_BUSY;
  2490. }
  2491. //
  2492. // Verify parameters of this request.
  2493. // Check that ending sector is on disc and
  2494. // that number of bytes to transfer is a multiple of
  2495. // the sector size.
  2496. //
  2497. startingOffset.QuadPart = currentIrpStack->Parameters.Read.ByteOffset.QuadPart +
  2498. transferByteCount;
  2499. if (!fdoExtension->DiskGeometry.BytesPerSector) {
  2500. fdoExtension->DiskGeometry.BytesPerSector = 2048;
  2501. }
  2502. if ((startingOffset.QuadPart > commonExtension->PartitionLength.QuadPart) ||
  2503. (transferByteCount & fdoExtension->DiskGeometry.BytesPerSector - 1)) {
  2504. //
  2505. // Fail request with status of invalid parameters.
  2506. //
  2507. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  2508. return STATUS_INVALID_PARAMETER;
  2509. }
  2510. return STATUS_SUCCESS;
  2511. } // end CdRomReadWriteVerification()
  2512. NTSTATUS
  2513. CdRomSwitchModeCompletion(
  2514. IN PDEVICE_OBJECT DeviceObject,
  2515. IN PIRP Irp,
  2516. IN PVOID Context
  2517. )
  2518. {
  2519. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  2520. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  2521. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  2522. PCDROM_DATA cdData = (PCDROM_DATA)(commonExtension->DriverData);
  2523. BOOLEAN use6Byte = TEST_FLAG(cdData->XAFlags, XA_USE_6_BYTE);
  2524. PIO_STACK_LOCATION realIrpStack;
  2525. PIO_STACK_LOCATION realIrpNextStack;
  2526. PSCSI_REQUEST_BLOCK srb = Context;
  2527. PIRP realIrp = NULL;
  2528. NTSTATUS status;
  2529. BOOLEAN retry;
  2530. //
  2531. // Extract the 'real' irp from the irpstack.
  2532. //
  2533. realIrp = (PIRP) irpStack->Parameters.Others.Argument2;
  2534. realIrpStack = IoGetCurrentIrpStackLocation(realIrp);
  2535. realIrpNextStack = IoGetNextIrpStackLocation(realIrp);
  2536. //
  2537. // Check SRB status for success of completing request.
  2538. //
  2539. if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
  2540. ULONG retryInterval;
  2541. TraceLog((CdromDebugTrace,
  2542. "CdRomSetVolumeIntermediateCompletion: Irp %p, Srb %p, Real Irp %p\n",
  2543. Irp,
  2544. srb,
  2545. realIrp));
  2546. //
  2547. // Release the queue if it is frozen.
  2548. //
  2549. if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
  2550. ClassReleaseQueue(DeviceObject);
  2551. }
  2552. retry = ClassInterpretSenseInfo(DeviceObject,
  2553. srb,
  2554. irpStack->MajorFunction,
  2555. irpStack->Parameters.DeviceIoControl.IoControlCode,
  2556. MAXIMUM_RETRIES - ((ULONG)(ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1),
  2557. &status,
  2558. &retryInterval);
  2559. //
  2560. // If the status is verified required and the this request
  2561. // should bypass verify required then retry the request.
  2562. //
  2563. if (realIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
  2564. status == STATUS_VERIFY_REQUIRED) {
  2565. status = STATUS_IO_DEVICE_ERROR;
  2566. retry = TRUE;
  2567. }
  2568. if (retry && ((ULONG)(ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1)--) {
  2569. if (((ULONG)(ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1)) {
  2570. //
  2571. // Retry request.
  2572. //
  2573. TraceLog((CdromDebugWarning,
  2574. "Retry request %p - Calling StartIo\n", Irp));
  2575. ExFreePool(srb->SenseInfoBuffer);
  2576. ExFreePool(srb->DataBuffer);
  2577. ExFreePool(srb);
  2578. if (Irp->MdlAddress) {
  2579. IoFreeMdl(Irp->MdlAddress);
  2580. }
  2581. IoFreeIrp(Irp);
  2582. //
  2583. // Call StartIo directly since IoStartNextPacket hasn't been called,
  2584. // the serialisation is still intact.
  2585. //
  2586. CdRomRetryRequest(fdoExtension,
  2587. realIrp,
  2588. retryInterval,
  2589. FALSE);
  2590. return STATUS_MORE_PROCESSING_REQUIRED;
  2591. }
  2592. //
  2593. // Exhausted retries. Fall through and complete the request with the appropriate status.
  2594. //
  2595. }
  2596. } else {
  2597. //
  2598. // Set status for successful request.
  2599. //
  2600. status = STATUS_SUCCESS;
  2601. }
  2602. if (NT_SUCCESS(status)) {
  2603. ULONG sectorSize, startingSector, transferByteCount;
  2604. PCDB cdb;
  2605. //
  2606. // Update device ext. to show which mode we are currently using.
  2607. //
  2608. sectorSize = cdData->BlockDescriptor.BlockLength[0] << 16;
  2609. sectorSize |= (cdData->BlockDescriptor.BlockLength[1] << 8);
  2610. sectorSize |= (cdData->BlockDescriptor.BlockLength[2]);
  2611. cdData->RawAccess = (sectorSize == RAW_SECTOR_SIZE) ? TRUE : FALSE;
  2612. //
  2613. // Free the old data buffer, mdl.
  2614. // reuse the SenseInfoBuffer and Srb
  2615. //
  2616. ExFreePool(srb->DataBuffer);
  2617. IoFreeMdl(Irp->MdlAddress);
  2618. IoFreeIrp(Irp);
  2619. //
  2620. // rebuild the srb.
  2621. //
  2622. cdb = (PCDB)srb->Cdb;
  2623. RtlZeroMemory(cdb, CDB12GENERIC_LENGTH);
  2624. if (cdData->RawAccess) {
  2625. PRAW_READ_INFO rawReadInfo =
  2626. (PRAW_READ_INFO)realIrpStack->Parameters.DeviceIoControl.Type3InputBuffer;
  2627. ULONG maximumTransferLength;
  2628. ULONG transferPages;
  2629. UCHAR min, sec, frame;
  2630. //
  2631. // Calculate starting offset.
  2632. //
  2633. startingSector = (ULONG)(rawReadInfo->DiskOffset.QuadPart >> fdoExtension->SectorShift);
  2634. transferByteCount = rawReadInfo->SectorCount * RAW_SECTOR_SIZE;
  2635. maximumTransferLength = fdoExtension->AdapterDescriptor->MaximumTransferLength;
  2636. transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(realIrp->MdlAddress),
  2637. transferByteCount);
  2638. //
  2639. // Determine if request is within limits imposed by miniport.
  2640. // If the request is larger than the miniport's capabilities, split it.
  2641. //
  2642. if (transferByteCount > maximumTransferLength ||
  2643. transferPages > fdoExtension->AdapterDescriptor->MaximumPhysicalPages) {
  2644. ExFreePool(srb->SenseInfoBuffer);
  2645. ExFreePool(srb);
  2646. realIrp->IoStatus.Information = 0;
  2647. realIrp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  2648. BAIL_OUT(realIrp);
  2649. CdRomCompleteIrpAndStartNextPacketSafely(DeviceObject, realIrp);
  2650. return STATUS_MORE_PROCESSING_REQUIRED;
  2651. }
  2652. srb->OriginalRequest = realIrp;
  2653. srb->SrbFlags = fdoExtension->SrbFlags;
  2654. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
  2655. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
  2656. srb->DataTransferLength = transferByteCount;
  2657. srb->TimeOutValue = fdoExtension->TimeOutValue;
  2658. srb->CdbLength = 10;
  2659. srb->DataBuffer = MmGetMdlVirtualAddress(realIrp->MdlAddress);
  2660. if (rawReadInfo->TrackMode == CDDA) {
  2661. if (TEST_FLAG(cdData->XAFlags, XA_PLEXTOR_CDDA)) {
  2662. srb->CdbLength = 12;
  2663. cdb->PLXTR_READ_CDDA.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
  2664. cdb->PLXTR_READ_CDDA.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
  2665. cdb->PLXTR_READ_CDDA.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
  2666. cdb->PLXTR_READ_CDDA.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
  2667. cdb->PLXTR_READ_CDDA.TransferBlockByte3 = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
  2668. cdb->PLXTR_READ_CDDA.TransferBlockByte2 = (UCHAR) (rawReadInfo->SectorCount >> 8);
  2669. cdb->PLXTR_READ_CDDA.TransferBlockByte1 = 0;
  2670. cdb->PLXTR_READ_CDDA.TransferBlockByte0 = 0;
  2671. cdb->PLXTR_READ_CDDA.SubCode = 0;
  2672. cdb->PLXTR_READ_CDDA.OperationCode = 0xD8;
  2673. } else if (TEST_FLAG(cdData->XAFlags, XA_NEC_CDDA)) {
  2674. cdb->NEC_READ_CDDA.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
  2675. cdb->NEC_READ_CDDA.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
  2676. cdb->NEC_READ_CDDA.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
  2677. cdb->NEC_READ_CDDA.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
  2678. cdb->NEC_READ_CDDA.TransferBlockByte1 = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
  2679. cdb->NEC_READ_CDDA.TransferBlockByte0 = (UCHAR) (rawReadInfo->SectorCount >> 8);
  2680. cdb->NEC_READ_CDDA.OperationCode = 0xD4;
  2681. }
  2682. } else {
  2683. cdb->CDB10.TransferBlocksMsb = (UCHAR) (rawReadInfo->SectorCount >> 8);
  2684. cdb->CDB10.TransferBlocksLsb = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
  2685. cdb->CDB10.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
  2686. cdb->CDB10.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
  2687. cdb->CDB10.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
  2688. cdb->CDB10.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
  2689. cdb->CDB10.OperationCode = SCSIOP_READ;
  2690. }
  2691. srb->SrbStatus = srb->ScsiStatus = 0;
  2692. irpStack = IoGetNextIrpStackLocation(realIrp);
  2693. irpStack->MajorFunction = IRP_MJ_SCSI;
  2694. irpStack->Parameters.Scsi.Srb = srb;
  2695. if (!(irpStack->Parameters.Others.Argument1)) {
  2696. //
  2697. // Only jam this in if it doesn't exist. The completion routines can
  2698. // call StartIo directly in the case of retries and resetting it will
  2699. // cause infinite loops.
  2700. //
  2701. irpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
  2702. }
  2703. //
  2704. // Set up IoCompletion routine address.
  2705. //
  2706. IoSetCompletionRoutine(realIrp,
  2707. CdRomXACompletion,
  2708. srb,
  2709. TRUE,
  2710. TRUE,
  2711. TRUE);
  2712. } else {
  2713. PSTORAGE_ADAPTER_DESCRIPTOR adapterDescriptor;
  2714. ULONG maximumTransferLength;
  2715. ULONG transferPages;
  2716. //
  2717. // a writable device must be MMC compliant, which supports
  2718. // READ_CD commands, so writes and mode switching should
  2719. // never occur on the same device.
  2720. //
  2721. ASSERT(realIrpStack->MajorFunction != IRP_MJ_WRITE);
  2722. //
  2723. // free the SRB and SenseInfoBuffer since they aren't used
  2724. // by either ClassBuildRequest() nor ClassSplitRequest().
  2725. //
  2726. ExFreePool(srb->SenseInfoBuffer);
  2727. ExFreePool(srb);
  2728. //
  2729. // Back to cooked sectors. Build and send a normal read.
  2730. // The real work for setting offsets was done in startio.
  2731. //
  2732. adapterDescriptor =
  2733. commonExtension->PartitionZeroExtension->AdapterDescriptor;
  2734. maximumTransferLength = adapterDescriptor->MaximumTransferLength;
  2735. transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
  2736. MmGetMdlVirtualAddress(realIrp->MdlAddress),
  2737. realIrpStack->Parameters.Read.Length);
  2738. if ((realIrpStack->Parameters.Read.Length > maximumTransferLength) ||
  2739. (transferPages > adapterDescriptor->MaximumPhysicalPages)) {
  2740. ULONG maxPages = adapterDescriptor->MaximumPhysicalPages;
  2741. if (maxPages != 0) {
  2742. maxPages --; // to account for page boundaries
  2743. }
  2744. TraceLog((CdromDebugTrace,
  2745. "CdromSwitchModeCompletion: Request greater than "
  2746. " maximum\n"));
  2747. TraceLog((CdromDebugTrace,
  2748. "CdromSwitchModeCompletion: Maximum is %lx\n",
  2749. maximumTransferLength));
  2750. TraceLog((CdromDebugTrace,
  2751. "CdromSwitchModeCompletion: Byte count is %lx\n",
  2752. realIrpStack->Parameters.Read.Length));
  2753. //
  2754. // Check that the maximum transfer length fits within
  2755. // the maximum number of pages the device can handle.
  2756. //
  2757. if (maximumTransferLength > maxPages << PAGE_SHIFT) {
  2758. maximumTransferLength = maxPages << PAGE_SHIFT;
  2759. }
  2760. //
  2761. // Check that maximum transfer size is not zero
  2762. //
  2763. if (maximumTransferLength == 0) {
  2764. maximumTransferLength = PAGE_SIZE;
  2765. }
  2766. //
  2767. // Request needs to be split. Completion of each portion
  2768. // of the request will fire off the next portion. The final
  2769. // request will signal Io to send a new request.
  2770. //
  2771. ClassSplitRequest(DeviceObject, realIrp, maximumTransferLength);
  2772. return STATUS_MORE_PROCESSING_REQUIRED;
  2773. } else {
  2774. //
  2775. // Build SRB and CDB for this IRP.
  2776. //
  2777. ClassBuildRequest(DeviceObject, realIrp);
  2778. }
  2779. }
  2780. //
  2781. // Call the port driver.
  2782. //
  2783. IoCallDriver(commonExtension->LowerDeviceObject, realIrp);
  2784. return STATUS_MORE_PROCESSING_REQUIRED;
  2785. }
  2786. //
  2787. // Update device Extension flags to indicate that XA isn't supported.
  2788. //
  2789. TraceLog((CdromDebugWarning,
  2790. "Device Cannot Support CDDA (but tested positive) "
  2791. "Now Clearing CDDA flags for FDO %p\n", DeviceObject));
  2792. SET_FLAG(cdData->XAFlags, XA_NOT_SUPPORTED);
  2793. CLEAR_FLAG(cdData->XAFlags, XA_PLEXTOR_CDDA);
  2794. CLEAR_FLAG(cdData->XAFlags, XA_NEC_CDDA);
  2795. //
  2796. // Deallocate srb and sense buffer.
  2797. //
  2798. if (srb) {
  2799. if (srb->DataBuffer) {
  2800. ExFreePool(srb->DataBuffer);
  2801. }
  2802. if (srb->SenseInfoBuffer) {
  2803. ExFreePool(srb->SenseInfoBuffer);
  2804. }
  2805. ExFreePool(srb);
  2806. }
  2807. if (Irp->PendingReturned) {
  2808. IoMarkIrpPending(Irp);
  2809. }
  2810. if (realIrp->PendingReturned) {
  2811. IoMarkIrpPending(realIrp);
  2812. }
  2813. if (Irp->MdlAddress) {
  2814. IoFreeMdl(Irp->MdlAddress);
  2815. }
  2816. IoFreeIrp(Irp);
  2817. //
  2818. // Set status in completing IRP.
  2819. //
  2820. realIrp->IoStatus.Status = status;
  2821. //
  2822. // Set the hard error if necessary.
  2823. //
  2824. if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
  2825. //
  2826. // Store DeviceObject for filesystem, and clear
  2827. // in IoStatus.Information field.
  2828. //
  2829. if (realIrp->Tail.Overlay.Thread) {
  2830. IoSetHardErrorOrVerifyDevice(realIrp, DeviceObject);
  2831. }
  2832. realIrp->IoStatus.Information = 0;
  2833. }
  2834. CdRomCompleteIrpAndStartNextPacketSafely(DeviceObject, realIrp);
  2835. return STATUS_MORE_PROCESSING_REQUIRED;
  2836. }
  2837. VOID
  2838. ScanForSpecialHandler(
  2839. PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  2840. ULONG_PTR HackFlags
  2841. )
  2842. {
  2843. PCOMMON_DEVICE_EXTENSION commonExtension;
  2844. PCDROM_DATA cdData;
  2845. PAGED_CODE();
  2846. CLEAR_FLAG(HackFlags, CDROM_HACK_INVALID_FLAGS);
  2847. commonExtension = &(FdoExtension->CommonExtension);
  2848. cdData = (PCDROM_DATA)(commonExtension->DriverData);
  2849. cdData->HackFlags = HackFlags;
  2850. return;
  2851. }
  2852. VOID
  2853. ScanForSpecial(
  2854. PDEVICE_OBJECT DeviceObject
  2855. )
  2856. /*++
  2857. Routine Description:
  2858. This function checks to see if an SCSI logical unit requires an special
  2859. initialization or error processing.
  2860. Arguments:
  2861. DeviceObject - Supplies the device object to be tested.
  2862. InquiryData - Supplies the inquiry data returned by the device of interest.
  2863. PortCapabilities - Supplies the capabilities of the device object.
  2864. Return Value:
  2865. None.
  2866. --*/
  2867. {
  2868. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
  2869. PCOMMON_DEVICE_EXTENSION commonExtension;
  2870. PCDROM_DATA cdData;
  2871. PAGED_CODE();
  2872. fdoExtension = DeviceObject->DeviceExtension;
  2873. commonExtension = DeviceObject->DeviceExtension;
  2874. cdData = (PCDROM_DATA)(commonExtension->DriverData);
  2875. //
  2876. // set our hack flags
  2877. //
  2878. ClassScanForSpecial(fdoExtension, CdromHackItems, ScanForSpecialHandler);
  2879. //
  2880. // All CDRom's can ignore the queue lock failure for power operations
  2881. // and do not require handling the SpinUp case (unknown result of sending
  2882. // a cdrom a START_UNIT command -- may eject disks?)
  2883. //
  2884. // We send the stop command mostly to stop outstanding asynch operations
  2885. // (like audio playback) from running when the system is powered off.
  2886. // Because of this and the unlikely chance that a PLAY command will be
  2887. // sent in the window between the STOP and the time the machine powers down
  2888. // we don't require queue locks. This is important because without them
  2889. // classpnp's power routines will send the START_STOP_UNIT command to the
  2890. // device whether or not it supports locking (atapi does not support locking
  2891. // and if we requested them we would end up not stopping audio on atapi
  2892. // devices).
  2893. //
  2894. SET_FLAG(fdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_DISABLE_SPIN_UP);
  2895. SET_FLAG(fdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_NO_QUEUE_LOCK);
  2896. if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_HITACHI_1750)
  2897. && ( fdoExtension->AdapterDescriptor->AdapterUsesPio )
  2898. ) {
  2899. //
  2900. // Read-ahead must be disabled in order to get this cdrom drive
  2901. // to work on scsi adapters that use PIO.
  2902. //
  2903. TraceLog((CdromDebugWarning,
  2904. "CdRom ScanForSpecial: Found Hitachi CDR-1750S.\n"));
  2905. //
  2906. // Setup an error handler to reinitialize the cd rom after it is reset.
  2907. //
  2908. cdData->ErrorHandler = HitachiProcessError;
  2909. //
  2910. // Lock down the hitachi error processing code.
  2911. //
  2912. MmLockPagableCodeSection(HitachiProcessError);
  2913. SET_FLAG(cdData->HackFlags, CDROM_HACK_LOCKED_PAGES);
  2914. } else if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_TOSHIBA_SD_W1101)) {
  2915. TraceLog((CdromDebugError,
  2916. "CdRom ScanForSpecial: Found Toshiba SD-W1101 DVD-RAM "
  2917. "-- This drive will *NOT* support DVD-ROM playback.\n"));
  2918. } else if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_HITACHI_GD_2000)) {
  2919. TraceLog((CdromDebugWarning,
  2920. "CdRom ScanForSpecial: Found Hitachi GD-2000\n"));
  2921. //
  2922. // Setup an error handler to spin up the drive when it idles out
  2923. // since it seems to like to fail to spin itself back up on its
  2924. // own for a REPORT_KEY command. It may also lose the AGIDs that
  2925. // it has given, which will result in DVD playback failures.
  2926. // This routine will just do what it can...
  2927. //
  2928. cdData->ErrorHandler = HitachiProcessErrorGD2000;
  2929. //
  2930. // this drive may require START_UNIT commands to spin
  2931. // the drive up when it's spun itself down.
  2932. //
  2933. SET_FLAG(fdoExtension->DeviceFlags, DEV_SAFE_START_UNIT);
  2934. //
  2935. // Lock down the hitachi error processing code.
  2936. //
  2937. MmLockPagableCodeSection(HitachiProcessErrorGD2000);
  2938. SET_FLAG(cdData->HackFlags, CDROM_HACK_LOCKED_PAGES);
  2939. } else if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_FUJITSU_FMCD_10x)) {
  2940. //
  2941. // When Read command is issued to FMCD-101 or FMCD-102 and there is a music
  2942. // cd in it. It takes longer time than SCSI_CDROM_TIMEOUT before returning
  2943. // error status.
  2944. //
  2945. fdoExtension->TimeOutValue = 20;
  2946. } else if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_DEC_RRD)) {
  2947. PMODE_PARM_READ_WRITE_DATA modeParameters;
  2948. SCSI_REQUEST_BLOCK srb;
  2949. PCDB cdb;
  2950. NTSTATUS status;
  2951. TraceLog((CdromDebugWarning,
  2952. "CdRom ScanForSpecial: Found DEC RRD.\n"));
  2953. cdData->IsDecRrd = TRUE;
  2954. //
  2955. // Setup an error handler to reinitialize the cd rom after it is reset?
  2956. //
  2957. //commonExtension->DevInfo->ClassError = DecRrdProcessError;
  2958. //
  2959. // Found a DEC RRD cd-rom. These devices do not pass MS HCT
  2960. // multi-media tests because the DEC firmware modifieds the block
  2961. // from the PC-standard 2K to 512. Change the block transfer size
  2962. // back to the PC-standard 2K by using a mode select command.
  2963. //
  2964. modeParameters = ExAllocatePoolWithTag(NonPagedPool,
  2965. sizeof(MODE_PARM_READ_WRITE_DATA),
  2966. CDROM_TAG_MODE_DATA
  2967. );
  2968. if (modeParameters == NULL) {
  2969. return;
  2970. }
  2971. RtlZeroMemory(modeParameters, sizeof(MODE_PARM_READ_WRITE_DATA));
  2972. RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
  2973. //
  2974. // Set the block length to 2K.
  2975. //
  2976. modeParameters->ParameterListHeader.BlockDescriptorLength =
  2977. sizeof(MODE_PARAMETER_BLOCK);
  2978. //
  2979. // Set block length to 2K (0x0800) in Parameter Block.
  2980. //
  2981. modeParameters->ParameterListBlock.BlockLength[0] = 0x00; //MSB
  2982. modeParameters->ParameterListBlock.BlockLength[1] = 0x08;
  2983. modeParameters->ParameterListBlock.BlockLength[2] = 0x00; //LSB
  2984. //
  2985. // Build the mode select CDB.
  2986. //
  2987. srb.CdbLength = 6;
  2988. srb.TimeOutValue = fdoExtension->TimeOutValue;
  2989. cdb = (PCDB)srb.Cdb;
  2990. cdb->MODE_SELECT.PFBit = 1;
  2991. cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
  2992. cdb->MODE_SELECT.ParameterListLength = HITACHI_MODE_DATA_SIZE;
  2993. //
  2994. // Send the request to the device.
  2995. //
  2996. status = ClassSendSrbSynchronous(DeviceObject,
  2997. &srb,
  2998. modeParameters,
  2999. sizeof(MODE_PARM_READ_WRITE_DATA),
  3000. TRUE);
  3001. if (!NT_SUCCESS(status)) {
  3002. TraceLog((CdromDebugWarning,
  3003. "CdRom ScanForSpecial: Setting DEC RRD to 2K block"
  3004. "size failed [%x]\n", status));
  3005. }
  3006. ExFreePool(modeParameters);
  3007. } else if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_TOSHIBA_XM_3xx)) {
  3008. SCSI_REQUEST_BLOCK srb;
  3009. PCDB cdb;
  3010. ULONG length;
  3011. PUCHAR buffer;
  3012. NTSTATUS status;
  3013. //
  3014. // Set the density code and the error handler.
  3015. //
  3016. length = (sizeof(MODE_READ_RECOVERY_PAGE) + MODE_BLOCK_DESC_LENGTH + MODE_HEADER_LENGTH);
  3017. RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
  3018. //
  3019. // Build the MODE SENSE CDB.
  3020. //
  3021. srb.CdbLength = 6;
  3022. cdb = (PCDB)srb.Cdb;
  3023. //
  3024. // Set timeout value from device extension.
  3025. //
  3026. srb.TimeOutValue = fdoExtension->TimeOutValue;
  3027. cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
  3028. cdb->MODE_SENSE.PageCode = 0x1;
  3029. // NOTE: purposely not setting DBD because it is what is needed.
  3030. cdb->MODE_SENSE.AllocationLength = (UCHAR)length;
  3031. buffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  3032. (sizeof(MODE_READ_RECOVERY_PAGE) + MODE_BLOCK_DESC_LENGTH + MODE_HEADER_LENGTH),
  3033. CDROM_TAG_MODE_DATA);
  3034. if (!buffer) {
  3035. return;
  3036. }
  3037. status = ClassSendSrbSynchronous(DeviceObject,
  3038. &srb,
  3039. buffer,
  3040. length,
  3041. FALSE);
  3042. ((PERROR_RECOVERY_DATA)buffer)->BlockDescriptor.DensityCode = 0x83;
  3043. ((PERROR_RECOVERY_DATA)buffer)->Header.ModeDataLength = 0x0;
  3044. RtlCopyMemory(&cdData->Header, buffer, sizeof(ERROR_RECOVERY_DATA));
  3045. RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
  3046. //
  3047. // Build the MODE SENSE CDB.
  3048. //
  3049. srb.CdbLength = 6;
  3050. cdb = (PCDB)srb.Cdb;
  3051. //
  3052. // Set timeout value from device extension.
  3053. //
  3054. srb.TimeOutValue = fdoExtension->TimeOutValue;
  3055. cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
  3056. cdb->MODE_SELECT.PFBit = 1;
  3057. cdb->MODE_SELECT.ParameterListLength = (UCHAR)length;
  3058. status = ClassSendSrbSynchronous(DeviceObject,
  3059. &srb,
  3060. buffer,
  3061. length,
  3062. TRUE);
  3063. if (!NT_SUCCESS(status)) {
  3064. TraceLog((CdromDebugWarning,
  3065. "Cdrom.ScanForSpecial: Setting density code on Toshiba failed [%x]\n",
  3066. status));
  3067. }
  3068. cdData->ErrorHandler = ToshibaProcessError;
  3069. //
  3070. // Lock down the toshiba error section.
  3071. //
  3072. MmLockPagableCodeSection(ToshibaProcessError);
  3073. SET_FLAG(cdData->HackFlags, CDROM_HACK_LOCKED_PAGES);
  3074. ExFreePool(buffer);
  3075. }
  3076. //
  3077. // Determine special CD-DA requirements.
  3078. //
  3079. if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_READ_CD_SUPPORTED)) {
  3080. SET_FLAG(cdData->XAFlags, XA_USE_READ_CD);
  3081. } else if (!TEST_FLAG(cdData->XAFlags, XA_USE_READ_CD)) {
  3082. if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_PLEXTOR_CDDA)) {
  3083. SET_FLAG(cdData->XAFlags, XA_PLEXTOR_CDDA);
  3084. } else if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_NEC_CDDA)) {
  3085. SET_FLAG(cdData->XAFlags, XA_NEC_CDDA);
  3086. }
  3087. }
  3088. if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_LOCKED_PAGES)) {
  3089. KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_ERROR_LEVEL,
  3090. "Locking pages for error handler\n"));
  3091. }
  3092. return;
  3093. }
  3094. VOID
  3095. HitachiProcessErrorGD2000(
  3096. PDEVICE_OBJECT Fdo,
  3097. PSCSI_REQUEST_BLOCK OriginalSrb,
  3098. NTSTATUS *Status,
  3099. BOOLEAN *Retry
  3100. )
  3101. /*++
  3102. Routine Description:
  3103. This routine checks the type of error. If the error suggests that the
  3104. drive has spun down and cannot reinitialize itself, send a
  3105. START_UNIT or READ to the device. This will force the drive to spin
  3106. up. This drive also loses the AGIDs it has granted when it spins down,
  3107. which may result in playback failure the first time around.
  3108. Arguments:
  3109. DeviceObject - Supplies a pointer to the device object.
  3110. Srb - Supplies a pointer to the failing Srb.
  3111. Status - return the final status for this command?
  3112. Retry - return if the command should be retried.
  3113. Return Value:
  3114. None.
  3115. --*/
  3116. {
  3117. PSENSE_DATA senseBuffer = OriginalSrb->SenseInfoBuffer;
  3118. UNREFERENCED_PARAMETER(Status);
  3119. UNREFERENCED_PARAMETER(Retry);
  3120. if (!TEST_FLAG(OriginalSrb->SrbStatus, SRB_STATUS_AUTOSENSE_VALID)) {
  3121. return;
  3122. }
  3123. if (((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_HARDWARE_ERROR) &&
  3124. (senseBuffer->AdditionalSenseCode == 0x44)) {
  3125. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
  3126. PIRP irp;
  3127. PIO_STACK_LOCATION irpStack;
  3128. PCOMPLETION_CONTEXT context;
  3129. PSCSI_REQUEST_BLOCK newSrb;
  3130. PCDB cdb;
  3131. TraceLog((CdromDebugWarning,
  3132. "HitachiProcessErrorGD2000 (%p) => Internal Target "
  3133. "Failure Detected -- spinning up drive\n", Fdo));
  3134. //
  3135. // the request should be retried because the device isn't ready
  3136. //
  3137. *Retry = TRUE;
  3138. *Status = STATUS_DEVICE_NOT_READY;
  3139. //
  3140. // send a START_STOP unit to spin up the drive
  3141. // NOTE: this temporarily violates the StartIo serialization
  3142. // mechanism, but the completion routine on this will NOT
  3143. // call StartNextPacket(), so it's a temporary disruption
  3144. // of the serialization only.
  3145. //
  3146. ClassSendStartUnit(Fdo);
  3147. }
  3148. return;
  3149. }
  3150. VOID
  3151. HitachiProcessError(
  3152. PDEVICE_OBJECT DeviceObject,
  3153. PSCSI_REQUEST_BLOCK Srb,
  3154. NTSTATUS *Status,
  3155. BOOLEAN *Retry
  3156. )
  3157. /*++
  3158. Routine Description:
  3159. This routine checks the type of error. If the error indicates CD-ROM the
  3160. CD-ROM needs to be reinitialized then a Mode sense command is sent to the
  3161. device. This command disables read-ahead for the device.
  3162. Arguments:
  3163. DeviceObject - Supplies a pointer to the device object.
  3164. Srb - Supplies a pointer to the failing Srb.
  3165. Status - Not used.
  3166. Retry - Not used.
  3167. Return Value:
  3168. None.
  3169. --*/
  3170. {
  3171. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  3172. PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer;
  3173. LARGE_INTEGER largeInt;
  3174. PUCHAR modePage;
  3175. PIO_STACK_LOCATION irpStack;
  3176. PIRP irp;
  3177. PSCSI_REQUEST_BLOCK srb;
  3178. PCOMPLETION_CONTEXT context;
  3179. PCDB cdb;
  3180. ULONG_PTR alignment;
  3181. UNREFERENCED_PARAMETER(Status);
  3182. UNREFERENCED_PARAMETER(Retry);
  3183. largeInt.QuadPart = (LONGLONG) 1;
  3184. //
  3185. // Check the status. The initialization command only needs to be sent
  3186. // if UNIT ATTENTION is returned.
  3187. //
  3188. if (!(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID)) {
  3189. //
  3190. // The drive does not require reinitialization.
  3191. //
  3192. return;
  3193. }
  3194. //
  3195. // Found an HITACHI cd-rom that does not work with PIO
  3196. // adapters when read-ahead is enabled. Read-ahead is disabled by
  3197. // a mode select command. The mode select page code is zero and the
  3198. // length is 6 bytes. All of the other bytes should be zero.
  3199. //
  3200. if ((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_UNIT_ATTENTION) {
  3201. TraceLog((CdromDebugWarning,
  3202. "HitachiProcessError: Reinitializing the CD-ROM.\n"));
  3203. //
  3204. // Send the special mode select command to disable read-ahead
  3205. // on the CD-ROM reader.
  3206. //
  3207. alignment = DeviceObject->AlignmentRequirement ?
  3208. DeviceObject->AlignmentRequirement : 1;
  3209. context = ExAllocatePoolWithTag(
  3210. NonPagedPool,
  3211. sizeof(COMPLETION_CONTEXT) + HITACHI_MODE_DATA_SIZE + (ULONG)alignment,
  3212. CDROM_TAG_HITACHI_ERROR
  3213. );
  3214. if (context == NULL) {
  3215. //
  3216. // If there is not enough memory to fulfill this request,
  3217. // simply return. A subsequent retry will fail and another
  3218. // chance to start the unit.
  3219. //
  3220. return;
  3221. }
  3222. context->DeviceObject = DeviceObject;
  3223. srb = &context->Srb;
  3224. RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
  3225. //
  3226. // Write length to SRB.
  3227. //
  3228. srb->Length = SCSI_REQUEST_BLOCK_SIZE;
  3229. //
  3230. // Set up SCSI bus address.
  3231. //
  3232. srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
  3233. srb->TimeOutValue = fdoExtension->TimeOutValue;
  3234. //
  3235. // Set the transfer length.
  3236. //
  3237. srb->DataTransferLength = HITACHI_MODE_DATA_SIZE;
  3238. srb->SrbFlags = fdoExtension->SrbFlags;
  3239. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_OUT);
  3240. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_AUTOSENSE);
  3241. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
  3242. //
  3243. // The data buffer must be aligned.
  3244. //
  3245. srb->DataBuffer = (PVOID) (((ULONG_PTR) (context + 1) + (alignment - 1)) &
  3246. ~(alignment - 1));
  3247. //
  3248. // Build the HITACHI read-ahead mode select CDB.
  3249. //
  3250. srb->CdbLength = 6;
  3251. cdb = (PCDB)srb->Cdb;
  3252. cdb->MODE_SENSE.LogicalUnitNumber = srb->Lun;
  3253. cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SELECT;
  3254. cdb->MODE_SENSE.AllocationLength = HITACHI_MODE_DATA_SIZE;
  3255. //
  3256. // Initialize the mode sense data.
  3257. //
  3258. modePage = srb->DataBuffer;
  3259. RtlZeroMemory(modePage, HITACHI_MODE_DATA_SIZE);
  3260. //
  3261. // Set the page length field to 6.
  3262. //
  3263. modePage[5] = 6;
  3264. //
  3265. // Build the asynchronous request to be sent to the port driver.
  3266. //
  3267. irp = IoBuildAsynchronousFsdRequest(IRP_MJ_WRITE,
  3268. DeviceObject,
  3269. srb->DataBuffer,
  3270. srb->DataTransferLength,
  3271. &largeInt,
  3272. NULL);
  3273. if (irp == NULL) {
  3274. //
  3275. // If there is not enough memory to fulfill this request,
  3276. // simply return. A subsequent retry will fail and another
  3277. // chance to start the unit.
  3278. //
  3279. ExFreePool(context);
  3280. return;
  3281. }
  3282. ClassAcquireRemoveLock(DeviceObject, irp);
  3283. IoSetCompletionRoutine(irp,
  3284. (PIO_COMPLETION_ROUTINE)ClassAsynchronousCompletion,
  3285. context,
  3286. TRUE,
  3287. TRUE,
  3288. TRUE);
  3289. irpStack = IoGetNextIrpStackLocation(irp);
  3290. irpStack->MajorFunction = IRP_MJ_SCSI;
  3291. srb->OriginalRequest = irp;
  3292. //
  3293. // Save SRB address in next stack for port driver.
  3294. //
  3295. irpStack->Parameters.Scsi.Srb = (PVOID)srb;
  3296. //
  3297. // Set up IRP Address.
  3298. //
  3299. (VOID)IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp);
  3300. }
  3301. }
  3302. NTSTATUS
  3303. ToshibaProcessErrorCompletion(
  3304. PDEVICE_OBJECT DeviceObject,
  3305. PIRP Irp,
  3306. PVOID Context
  3307. )
  3308. /*++
  3309. Routine Description:
  3310. Completion routine for the ClassError routine to handle older Toshiba units
  3311. that require setting the density code.
  3312. Arguments:
  3313. DeviceObject - Supplies a pointer to the device object.
  3314. Irp - Pointer to irp created to set the density code.
  3315. Context - Supplies a pointer to the Mode Select Srb.
  3316. Return Value:
  3317. STATUS_MORE_PROCESSING_REQUIRED
  3318. --*/
  3319. {
  3320. PSCSI_REQUEST_BLOCK srb = Context;
  3321. //
  3322. // Free all of the allocations.
  3323. //
  3324. ClassReleaseRemoveLock(DeviceObject, Irp);
  3325. ExFreePool(srb->DataBuffer);
  3326. ExFreePool(srb);
  3327. IoFreeMdl(Irp->MdlAddress);
  3328. IoFreeIrp(Irp);
  3329. //
  3330. // Indicate the I/O system should stop processing the Irp completion.
  3331. //
  3332. return STATUS_MORE_PROCESSING_REQUIRED;
  3333. }
  3334. VOID
  3335. ToshibaProcessError(
  3336. PDEVICE_OBJECT DeviceObject,
  3337. PSCSI_REQUEST_BLOCK Srb,
  3338. NTSTATUS *Status,
  3339. BOOLEAN *Retry
  3340. )
  3341. /*++
  3342. Routine Description:
  3343. This routine checks the type of error. If the error indicates a unit attention,
  3344. the density code needs to be set via a Mode select command.
  3345. Arguments:
  3346. DeviceObject - Supplies a pointer to the device object.
  3347. Srb - Supplies a pointer to the failing Srb.
  3348. Status - Not used.
  3349. Retry - Not used.
  3350. Return Value:
  3351. None.
  3352. --*/
  3353. {
  3354. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  3355. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  3356. PCDROM_DATA cdData = (PCDROM_DATA)(commonExtension->DriverData);
  3357. PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer;
  3358. PIO_STACK_LOCATION irpStack;
  3359. PIRP irp;
  3360. PSCSI_REQUEST_BLOCK srb;
  3361. ULONG length;
  3362. PCDB cdb;
  3363. PUCHAR dataBuffer;
  3364. if (!(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID)) {
  3365. return;
  3366. }
  3367. //
  3368. // The Toshiba's require the density code to be set on power up and media changes.
  3369. //
  3370. if ((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_UNIT_ATTENTION) {
  3371. irp = IoAllocateIrp((CCHAR)(DeviceObject->StackSize+1),
  3372. FALSE);
  3373. if (!irp) {
  3374. return;
  3375. }
  3376. srb = ExAllocatePoolWithTag(NonPagedPool,
  3377. sizeof(SCSI_REQUEST_BLOCK),
  3378. CDROM_TAG_TOSHIBA_ERROR);
  3379. if (!srb) {
  3380. IoFreeIrp(irp);
  3381. return;
  3382. }
  3383. length = sizeof(ERROR_RECOVERY_DATA);
  3384. dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  3385. length,
  3386. CDROM_TAG_TOSHIBA_ERROR);
  3387. if (!dataBuffer) {
  3388. ExFreePool(srb);
  3389. IoFreeIrp(irp);
  3390. return;
  3391. }
  3392. irp->MdlAddress = IoAllocateMdl(dataBuffer,
  3393. length,
  3394. FALSE,
  3395. FALSE,
  3396. (PIRP) NULL);
  3397. if (!irp->MdlAddress) {
  3398. ExFreePool(srb);
  3399. ExFreePool(dataBuffer);
  3400. IoFreeIrp(irp);
  3401. return;
  3402. }
  3403. //
  3404. // Prepare the MDL
  3405. //
  3406. MmBuildMdlForNonPagedPool(irp->MdlAddress);
  3407. RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
  3408. srb->DataBuffer = dataBuffer;
  3409. cdb = (PCDB)srb->Cdb;
  3410. //
  3411. // Set up the irp.
  3412. //
  3413. IoSetNextIrpStackLocation(irp);
  3414. irp->IoStatus.Status = STATUS_SUCCESS;
  3415. irp->IoStatus.Information = 0;
  3416. irp->Flags = 0;
  3417. irp->UserBuffer = NULL;
  3418. //
  3419. // Save the device object and irp in a private stack location.
  3420. //
  3421. irpStack = IoGetCurrentIrpStackLocation(irp);
  3422. irpStack->DeviceObject = DeviceObject;
  3423. //
  3424. // Construct the IRP stack for the lower level driver.
  3425. //
  3426. irpStack = IoGetNextIrpStackLocation(irp);
  3427. irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  3428. irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_OUT;
  3429. irpStack->Parameters.Scsi.Srb = srb;
  3430. IoSetCompletionRoutine(irp,
  3431. ToshibaProcessErrorCompletion,
  3432. srb,
  3433. TRUE,
  3434. TRUE,
  3435. TRUE);
  3436. ClassAcquireRemoveLock(DeviceObject, irp);
  3437. srb->Length = SCSI_REQUEST_BLOCK_SIZE;
  3438. srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
  3439. srb->SrbStatus = srb->ScsiStatus = 0;
  3440. srb->NextSrb = 0;
  3441. srb->OriginalRequest = irp;
  3442. srb->SenseInfoBufferLength = 0;
  3443. //
  3444. // Set the transfer length.
  3445. //
  3446. srb->DataTransferLength = length;
  3447. srb->SrbFlags = fdoExtension->SrbFlags;
  3448. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_OUT);
  3449. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_AUTOSENSE);
  3450. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
  3451. SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE);
  3452. srb->CdbLength = 6;
  3453. cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
  3454. cdb->MODE_SELECT.PFBit = 1;
  3455. cdb->MODE_SELECT.ParameterListLength = (UCHAR)length;
  3456. //
  3457. // Copy the Mode page into the databuffer.
  3458. //
  3459. RtlCopyMemory(srb->DataBuffer, &cdData->Header, length);
  3460. //
  3461. // Set the density code.
  3462. //
  3463. ((PERROR_RECOVERY_DATA)srb->DataBuffer)->BlockDescriptor.DensityCode = 0x83;
  3464. IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp);
  3465. }
  3466. }
  3467. BOOLEAN
  3468. CdRomIsPlayActive(
  3469. IN PDEVICE_OBJECT DeviceObject
  3470. )
  3471. /*++
  3472. Routine Description:
  3473. This routine determines if the cd is currently playing music.
  3474. Arguments:
  3475. DeviceObject - Device object to test.
  3476. Return Value:
  3477. TRUE if the device is playing music.
  3478. --*/
  3479. {
  3480. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  3481. IO_STATUS_BLOCK ioStatus;
  3482. PSUB_Q_CURRENT_POSITION currentBuffer;
  3483. PAGED_CODE();
  3484. //
  3485. // if we don't think it is playing audio, don't bother checking.
  3486. //
  3487. if (!PLAY_ACTIVE(fdoExtension)) {
  3488. return(FALSE);
  3489. }
  3490. currentBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  3491. sizeof(SUB_Q_CURRENT_POSITION),
  3492. CDROM_TAG_PLAY_ACTIVE);
  3493. if (currentBuffer == NULL) {
  3494. return(FALSE);
  3495. }
  3496. ((PCDROM_SUB_Q_DATA_FORMAT) currentBuffer)->Format = IOCTL_CDROM_CURRENT_POSITION;
  3497. ((PCDROM_SUB_Q_DATA_FORMAT) currentBuffer)->Track = 0;
  3498. //
  3499. // Build the synchronous request to be sent to ourself
  3500. // to perform the request.
  3501. //
  3502. ClassSendDeviceIoControlSynchronous(
  3503. IOCTL_CDROM_READ_Q_CHANNEL,
  3504. DeviceObject,
  3505. currentBuffer,
  3506. sizeof(CDROM_SUB_Q_DATA_FORMAT),
  3507. sizeof(SUB_Q_CURRENT_POSITION),
  3508. FALSE,
  3509. &ioStatus);
  3510. if (!NT_SUCCESS(ioStatus.Status)) {
  3511. ExFreePool(currentBuffer);
  3512. return FALSE;
  3513. }
  3514. //
  3515. // should update the playactive flag here.
  3516. //
  3517. if (currentBuffer->Header.AudioStatus == AUDIO_STATUS_IN_PROGRESS) {
  3518. PLAY_ACTIVE(fdoExtension) = TRUE;
  3519. } else {
  3520. PLAY_ACTIVE(fdoExtension) = FALSE;
  3521. }
  3522. ExFreePool(currentBuffer);
  3523. return(PLAY_ACTIVE(fdoExtension));
  3524. }
  3525. VOID
  3526. CdRomTickHandler(
  3527. IN PDEVICE_OBJECT DeviceObject
  3528. )
  3529. /*++
  3530. Routine Description:
  3531. This routine handles the once per second timer provided by the
  3532. Io subsystem. It is used to do delayed retries for cdroms.
  3533. Arguments:
  3534. DeviceObject - what to check.
  3535. Return Value:
  3536. None.
  3537. --*/
  3538. {
  3539. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  3540. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  3541. ULONG isRemoved;
  3542. KIRQL oldIrql;
  3543. PIRP irp;
  3544. PIRP heldIrpList;
  3545. PIRP nextIrp;
  3546. PLIST_ENTRY listEntry;
  3547. PCDROM_DATA cddata;
  3548. PIO_STACK_LOCATION irpStack;
  3549. UCHAR uniqueAddress;
  3550. isRemoved = ClassAcquireRemoveLock(DeviceObject, (PIRP) &uniqueAddress);
  3551. //
  3552. // We stop the timer before deleting the device. It's safe to keep going
  3553. // if the flag value is REMOVE_PENDING because the removal thread will be
  3554. // blocked trying to stop the timer.
  3555. //
  3556. ASSERT(isRemoved != REMOVE_COMPLETE);
  3557. //
  3558. // This routine is reasonably safe even if the device object has a pending
  3559. // remove
  3560. cddata = commonExtension->DriverData;
  3561. //
  3562. // Since cdrom is completely synchronized there can never be more than one
  3563. // irp delayed for retry at any time.
  3564. //
  3565. KeAcquireSpinLock(&(cddata->DelayedRetrySpinLock), &oldIrql);
  3566. if(cddata->DelayedRetryIrp != NULL) {
  3567. PIRP irp = cddata->DelayedRetryIrp;
  3568. //
  3569. // If we've got a delayed retry at this point then there had beter
  3570. // be an interval for it.
  3571. //
  3572. ASSERT(cddata->DelayedRetryInterval != 0);
  3573. cddata->DelayedRetryInterval--;
  3574. if(isRemoved) {
  3575. //
  3576. // This device is removed - flush the timer queue
  3577. //
  3578. cddata->DelayedRetryIrp = NULL;
  3579. cddata->DelayedRetryInterval = 0;
  3580. KeReleaseSpinLock(&(cddata->DelayedRetrySpinLock), oldIrql);
  3581. ClassReleaseRemoveLock(DeviceObject, irp);
  3582. ClassCompleteRequest(DeviceObject, irp, IO_CD_ROM_INCREMENT);
  3583. } else if (cddata->DelayedRetryInterval == 0) {
  3584. //
  3585. // Submit this IRP to the lower driver. This IRP does not
  3586. // need to be remembered here. It will be handled again when
  3587. // it completes.
  3588. //
  3589. cddata->DelayedRetryIrp = NULL;
  3590. KeReleaseSpinLock(&(cddata->DelayedRetrySpinLock), oldIrql);
  3591. TraceLog((CdromDebugWarning,
  3592. "CdRomTickHandler: Reissuing request %p (thread = %p)\n",
  3593. irp,
  3594. irp->Tail.Overlay.Thread));
  3595. //
  3596. // feed this to the appropriate port driver
  3597. //
  3598. CdRomRerunRequest(fdoExtension, irp, cddata->DelayedRetryResend);
  3599. } else {
  3600. KeReleaseSpinLock(&(cddata->DelayedRetrySpinLock), oldIrql);
  3601. }
  3602. } else {
  3603. KeReleaseSpinLock(&(cddata->DelayedRetrySpinLock), oldIrql);
  3604. }
  3605. ClassReleaseRemoveLock(DeviceObject, (PIRP) &uniqueAddress);
  3606. }
  3607. NTSTATUS
  3608. CdRomUpdateGeometryCompletion(
  3609. PDEVICE_OBJECT DeviceObject,
  3610. PIRP Irp,
  3611. PVOID Context
  3612. )
  3613. /*++
  3614. Routine Description:
  3615. This routine andles the completion of the test unit ready irps
  3616. used to determine if the media has changed. If the media has
  3617. changed, this code signals the named event to wake up other
  3618. system services that react to media change (aka AutoPlay).
  3619. Arguments:
  3620. DeviceObject - the object for the completion
  3621. Irp - the IRP being completed
  3622. Context - the SRB from the IRP
  3623. Return Value:
  3624. NTSTATUS
  3625. --*/
  3626. {
  3627. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
  3628. PCOMMON_DEVICE_EXTENSION commonExtension;
  3629. PSCSI_REQUEST_BLOCK srb = (PSCSI_REQUEST_BLOCK) Context;
  3630. PREAD_CAPACITY_DATA readCapacityBuffer;
  3631. PIO_STACK_LOCATION irpStack;
  3632. NTSTATUS status;
  3633. BOOLEAN retry;
  3634. ULONG retryCount;
  3635. ULONG lastSector;
  3636. PIRP originalIrp;
  3637. PCDROM_DATA cddata;
  3638. UCHAR uniqueAddress;
  3639. //
  3640. // Get items saved in the private IRP stack location.
  3641. //
  3642. irpStack = IoGetCurrentIrpStackLocation(Irp);
  3643. retryCount = (ULONG)(ULONG_PTR) irpStack->Parameters.Others.Argument1;
  3644. originalIrp = (PIRP) irpStack->Parameters.Others.Argument2;
  3645. if (!DeviceObject) {
  3646. DeviceObject = irpStack->DeviceObject;
  3647. }
  3648. ASSERT(DeviceObject);
  3649. fdoExtension = DeviceObject->DeviceExtension;
  3650. commonExtension = DeviceObject->DeviceExtension;
  3651. cddata = commonExtension->DriverData;
  3652. readCapacityBuffer = srb->DataBuffer;
  3653. if ((NT_SUCCESS(Irp->IoStatus.Status)) && (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_SUCCESS)) {
  3654. CdRomInterpretReadCapacity(DeviceObject, readCapacityBuffer);
  3655. } else {
  3656. ULONG retryInterval;
  3657. TraceLog((CdromDebugWarning,
  3658. "CdRomUpdateGeometryCompletion: [%p] unsuccessful "
  3659. "completion of buddy-irp %p (status - %lx)\n",
  3660. originalIrp, Irp, Irp->IoStatus.Status));
  3661. if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
  3662. ClassReleaseQueue(DeviceObject);
  3663. }
  3664. retry = ClassInterpretSenseInfo(DeviceObject,
  3665. srb,
  3666. IRP_MJ_SCSI,
  3667. 0,
  3668. retryCount,
  3669. &status,
  3670. &retryInterval);
  3671. if (retry) {
  3672. retryCount--;
  3673. if ((retryCount) && (commonExtension->IsRemoved == NO_REMOVE)) {
  3674. PCDB cdb;
  3675. TraceLog((CdromDebugWarning,
  3676. "CdRomUpdateGeometryCompletion: [%p] Retrying "
  3677. "request %p .. thread is %p\n",
  3678. originalIrp, Irp, Irp->Tail.Overlay.Thread));
  3679. //
  3680. // set up a one shot timer to get this process started over
  3681. //
  3682. irpStack->Parameters.Others.Argument1 = ULongToPtr( retryCount );
  3683. irpStack->Parameters.Others.Argument2 = (PVOID) originalIrp;
  3684. irpStack->Parameters.Others.Argument3 = (PVOID) 2;
  3685. //
  3686. // Setup the IRP to be submitted again in the timer routine.
  3687. //
  3688. irpStack = IoGetNextIrpStackLocation(Irp);
  3689. irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  3690. irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
  3691. irpStack->Parameters.Scsi.Srb = srb;
  3692. IoSetCompletionRoutine(Irp,
  3693. CdRomUpdateGeometryCompletion,
  3694. srb,
  3695. TRUE,
  3696. TRUE,
  3697. TRUE);
  3698. //
  3699. // Set up the SRB for read capacity.
  3700. //
  3701. srb->CdbLength = 10;
  3702. srb->TimeOutValue = fdoExtension->TimeOutValue;
  3703. srb->SrbStatus = srb->ScsiStatus = 0;
  3704. srb->NextSrb = 0;
  3705. srb->Length = SCSI_REQUEST_BLOCK_SIZE;
  3706. srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
  3707. srb->SrbFlags = fdoExtension->SrbFlags;
  3708. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
  3709. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
  3710. srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
  3711. //
  3712. // Set up the CDB
  3713. //
  3714. cdb = (PCDB) &srb->Cdb[0];
  3715. cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
  3716. //
  3717. // Requests queued onto this list will be sent to the
  3718. // lower level driver during CdRomTickHandler
  3719. //
  3720. CdRomRetryRequest(fdoExtension, Irp, retryInterval, TRUE);
  3721. return STATUS_MORE_PROCESSING_REQUIRED;
  3722. }
  3723. if (commonExtension->IsRemoved != NO_REMOVE) {
  3724. //
  3725. // We cannot retry the request. Fail it.
  3726. //
  3727. originalIrp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
  3728. } else {
  3729. //
  3730. // This has been bounced for a number of times. Error the
  3731. // original request.
  3732. //
  3733. originalIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  3734. RtlZeroMemory(&(fdoExtension->DiskGeometry),
  3735. sizeof(DISK_GEOMETRY));
  3736. fdoExtension->DiskGeometry.BytesPerSector = 2048;
  3737. fdoExtension->SectorShift = 11;
  3738. commonExtension->PartitionLength.QuadPart =
  3739. (LONGLONG)(0x7fffffff);
  3740. fdoExtension->DiskGeometry.MediaType = RemovableMedia;
  3741. }
  3742. } else {
  3743. //
  3744. // Set up reasonable defaults
  3745. //
  3746. RtlZeroMemory(&(fdoExtension->DiskGeometry),
  3747. sizeof(DISK_GEOMETRY));
  3748. fdoExtension->DiskGeometry.BytesPerSector = 2048;
  3749. fdoExtension->SectorShift = 11;
  3750. commonExtension->PartitionLength.QuadPart = (LONGLONG)(0x7fffffff);
  3751. fdoExtension->DiskGeometry.MediaType = RemovableMedia;
  3752. }
  3753. }
  3754. //
  3755. // Free resources held.
  3756. //
  3757. ExFreePool(srb->SenseInfoBuffer);
  3758. ExFreePool(srb->DataBuffer);
  3759. ExFreePool(srb);
  3760. if (Irp->MdlAddress) {
  3761. IoFreeMdl(Irp->MdlAddress);
  3762. }
  3763. IoFreeIrp(Irp);
  3764. Irp = NULL;
  3765. if (originalIrp->Tail.Overlay.Thread) {
  3766. TraceLog((CdromDebugTrace,
  3767. "CdRomUpdateGeometryCompletion: [%p] completing "
  3768. "original IRP\n", originalIrp));
  3769. } else {
  3770. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugError,
  3771. "CdRomUpdateGeometryCompletion: completing irp %p which has "
  3772. "no thread\n", originalIrp));
  3773. }
  3774. {
  3775. // NOTE: should the original irp be sent down to the device object?
  3776. // it probably should if the SL_OVERRIDER_VERIFY_VOLUME flag
  3777. // is set!
  3778. KIRQL oldIrql;
  3779. PIO_STACK_LOCATION realIrpStack;
  3780. realIrpStack = IoGetCurrentIrpStackLocation(originalIrp);
  3781. oldIrql = KeRaiseIrqlToDpcLevel();
  3782. if (TEST_FLAG(realIrpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME)) {
  3783. CdRomStartIo(DeviceObject, originalIrp);
  3784. } else {
  3785. originalIrp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
  3786. originalIrp->IoStatus.Information = 0;
  3787. CdRomCompleteIrpAndStartNextPacketSafely(DeviceObject, originalIrp);
  3788. }
  3789. KeLowerIrql(oldIrql);
  3790. }
  3791. return STATUS_MORE_PROCESSING_REQUIRED;
  3792. }
  3793. NTSTATUS
  3794. CdRomUpdateCapacity(
  3795. IN PFUNCTIONAL_DEVICE_EXTENSION DeviceExtension,
  3796. IN PIRP IrpToComplete,
  3797. IN OPTIONAL PKEVENT IoctlEvent
  3798. )
  3799. /*++
  3800. Routine Description:
  3801. This routine updates the capacity of the disk as recorded in the device extension.
  3802. It also completes the IRP given with STATUS_VERIFY_REQUIRED. This routine is called
  3803. when a media change has occurred and it is necessary to determine the capacity of the
  3804. new media prior to the next access.
  3805. Arguments:
  3806. DeviceExtension - the device to update
  3807. IrpToComplete - the request that needs to be completed when done.
  3808. Return Value:
  3809. NTSTATUS
  3810. --*/
  3811. {
  3812. PCOMMON_DEVICE_EXTENSION commonExtension = (PCOMMON_DEVICE_EXTENSION) DeviceExtension;
  3813. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION) DeviceExtension;
  3814. PCDB cdb;
  3815. PIRP irp;
  3816. PSCSI_REQUEST_BLOCK srb;
  3817. PREAD_CAPACITY_DATA capacityBuffer;
  3818. PIO_STACK_LOCATION irpStack;
  3819. PUCHAR senseBuffer;
  3820. NTSTATUS status;
  3821. irp = IoAllocateIrp((CCHAR)(commonExtension->DeviceObject->StackSize+1),
  3822. FALSE);
  3823. if (irp) {
  3824. srb = ExAllocatePoolWithTag(NonPagedPool,
  3825. sizeof(SCSI_REQUEST_BLOCK),
  3826. CDROM_TAG_UPDATE_CAP);
  3827. if (srb) {
  3828. capacityBuffer = ExAllocatePoolWithTag(
  3829. NonPagedPoolCacheAligned,
  3830. sizeof(READ_CAPACITY_DATA),
  3831. CDROM_TAG_UPDATE_CAP);
  3832. if (capacityBuffer) {
  3833. senseBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  3834. SENSE_BUFFER_SIZE,
  3835. CDROM_TAG_UPDATE_CAP);
  3836. if (senseBuffer) {
  3837. irp->MdlAddress = IoAllocateMdl(capacityBuffer,
  3838. sizeof(READ_CAPACITY_DATA),
  3839. FALSE,
  3840. FALSE,
  3841. (PIRP) NULL);
  3842. if (irp->MdlAddress) {
  3843. //
  3844. // Have all resources. Set up the IRP to send for the capacity.
  3845. //
  3846. IoSetNextIrpStackLocation(irp);
  3847. irp->IoStatus.Status = STATUS_SUCCESS;
  3848. irp->IoStatus.Information = 0;
  3849. irp->Flags = 0;
  3850. irp->UserBuffer = NULL;
  3851. //
  3852. // Save the device object and retry count in a private stack location.
  3853. //
  3854. irpStack = IoGetCurrentIrpStackLocation(irp);
  3855. irpStack->DeviceObject = commonExtension->DeviceObject;
  3856. irpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
  3857. irpStack->Parameters.Others.Argument2 = (PVOID) IrpToComplete;
  3858. //
  3859. // Construct the IRP stack for the lower level driver.
  3860. //
  3861. irpStack = IoGetNextIrpStackLocation(irp);
  3862. irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  3863. irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
  3864. irpStack->Parameters.Scsi.Srb = srb;
  3865. IoSetCompletionRoutine(irp,
  3866. CdRomUpdateGeometryCompletion,
  3867. srb,
  3868. TRUE,
  3869. TRUE,
  3870. TRUE);
  3871. //
  3872. // Prepare the MDL
  3873. //
  3874. MmBuildMdlForNonPagedPool(irp->MdlAddress);
  3875. //
  3876. // Set up the SRB for read capacity.
  3877. //
  3878. RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
  3879. RtlZeroMemory(senseBuffer, SENSE_BUFFER_SIZE);
  3880. srb->CdbLength = 10;
  3881. srb->TimeOutValue = DeviceExtension->TimeOutValue;
  3882. srb->SrbStatus = srb->ScsiStatus = 0;
  3883. srb->NextSrb = 0;
  3884. srb->Length = SCSI_REQUEST_BLOCK_SIZE;
  3885. srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
  3886. srb->SrbFlags = DeviceExtension->SrbFlags;
  3887. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
  3888. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
  3889. srb->DataBuffer = capacityBuffer;
  3890. srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
  3891. srb->OriginalRequest = irp;
  3892. srb->SenseInfoBuffer = senseBuffer;
  3893. srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
  3894. //
  3895. // Set up the CDB
  3896. //
  3897. cdb = (PCDB) &srb->Cdb[0];
  3898. cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
  3899. //
  3900. // Set the return value in the IRP that will be completed
  3901. // upon completion of the read capacity.
  3902. //
  3903. IrpToComplete->IoStatus.Status = STATUS_IO_DEVICE_ERROR;
  3904. IoMarkIrpPending(IrpToComplete);
  3905. IoCallDriver(commonExtension->LowerDeviceObject, irp);
  3906. //
  3907. // status is not checked because the completion routine for this
  3908. // IRP will always get called and it will free the resources.
  3909. //
  3910. return STATUS_PENDING;
  3911. } else {
  3912. ExFreePool(senseBuffer);
  3913. ExFreePool(capacityBuffer);
  3914. ExFreePool(srb);
  3915. IoFreeIrp(irp);
  3916. }
  3917. } else {
  3918. ExFreePool(capacityBuffer);
  3919. ExFreePool(srb);
  3920. IoFreeIrp(irp);
  3921. }
  3922. } else {
  3923. ExFreePool(srb);
  3924. IoFreeIrp(irp);
  3925. }
  3926. } else {
  3927. IoFreeIrp(irp);
  3928. }
  3929. }
  3930. //
  3931. // complete the original irp with a failure.
  3932. // ISSUE-2000/07/05-henrygab - find a way to avoid failure.
  3933. //
  3934. RtlZeroMemory(&(fdoExtension->DiskGeometry),
  3935. sizeof(DISK_GEOMETRY));
  3936. fdoExtension->DiskGeometry.BytesPerSector = 2048;
  3937. fdoExtension->SectorShift = 11;
  3938. commonExtension->PartitionLength.QuadPart =
  3939. (LONGLONG)(0x7fffffff);
  3940. fdoExtension->DiskGeometry.MediaType = RemovableMedia;
  3941. IrpToComplete->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  3942. IrpToComplete->IoStatus.Information = 0;
  3943. BAIL_OUT(IrpToComplete);
  3944. CdRomCompleteIrpAndStartNextPacketSafely(commonExtension->DeviceObject,
  3945. IrpToComplete);
  3946. return STATUS_INSUFFICIENT_RESOURCES;
  3947. }
  3948. NTSTATUS
  3949. CdRomRemoveDevice(
  3950. IN PDEVICE_OBJECT DeviceObject,
  3951. IN UCHAR Type
  3952. )
  3953. /*++
  3954. Routine Description:
  3955. This routine is responsible for releasing any resources in use by the
  3956. cdrom driver and shutting down it's timer routine. This routine is called
  3957. when all outstanding requests have been completed and the device has
  3958. disappeared - no requests may be issued to the lower drivers.
  3959. Arguments:
  3960. DeviceObject - the device object being removed
  3961. Return Value:
  3962. none - this routine may not fail
  3963. --*/
  3964. {
  3965. PFUNCTIONAL_DEVICE_EXTENSION deviceExtension =
  3966. DeviceObject->DeviceExtension;
  3967. PCDROM_DATA cdData = deviceExtension->CommonExtension.DriverData;
  3968. PAGED_CODE();
  3969. if((Type == IRP_MN_QUERY_REMOVE_DEVICE) ||
  3970. (Type == IRP_MN_CANCEL_REMOVE_DEVICE)) {
  3971. return STATUS_SUCCESS;
  3972. }
  3973. if(cdData->DelayedRetryIrp != NULL) {
  3974. cdData->DelayedRetryInterval = 1;
  3975. CdRomTickHandler(DeviceObject);
  3976. }
  3977. CdRomDeAllocateMmcResources(DeviceObject);
  3978. if (deviceExtension->DeviceDescriptor) {
  3979. ExFreePool(deviceExtension->DeviceDescriptor);
  3980. deviceExtension->DeviceDescriptor = NULL;
  3981. }
  3982. if (deviceExtension->AdapterDescriptor) {
  3983. ExFreePool(deviceExtension->AdapterDescriptor);
  3984. deviceExtension->AdapterDescriptor = NULL;
  3985. }
  3986. if (deviceExtension->SenseData) {
  3987. ExFreePool(deviceExtension->SenseData);
  3988. deviceExtension->SenseData = NULL;
  3989. }
  3990. ClassDeleteSrbLookasideList(&deviceExtension->CommonExtension);
  3991. if(cdData->CdromInterfaceString.Buffer != NULL) {
  3992. IoSetDeviceInterfaceState(
  3993. &(cdData->CdromInterfaceString),
  3994. FALSE);
  3995. RtlFreeUnicodeString(&(cdData->CdromInterfaceString));
  3996. RtlInitUnicodeString(&(cdData->CdromInterfaceString), NULL);
  3997. }
  3998. if(cdData->VolumeInterfaceString.Buffer != NULL) {
  3999. IoSetDeviceInterfaceState(
  4000. &(cdData->VolumeInterfaceString),
  4001. FALSE);
  4002. RtlFreeUnicodeString(&(cdData->VolumeInterfaceString));
  4003. RtlInitUnicodeString(&(cdData->VolumeInterfaceString), NULL);
  4004. }
  4005. CdRomDeleteWellKnownName(DeviceObject);
  4006. ASSERT(cdData->DelayedRetryIrp == NULL);
  4007. if(Type == IRP_MN_REMOVE_DEVICE) {
  4008. if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_LOCKED_PAGES)) {
  4009. //
  4010. // unlock locked pages by locking (to get Mm pointer)
  4011. // and then unlocking twice.
  4012. //
  4013. PVOID locked;
  4014. if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_HITACHI_1750)) {
  4015. locked = MmLockPagableCodeSection(HitachiProcessError);
  4016. } else if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_HITACHI_GD_2000)) {
  4017. locked = MmLockPagableCodeSection(HitachiProcessErrorGD2000);
  4018. } else if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_TOSHIBA_XM_3xx )) {
  4019. locked = MmLockPagableCodeSection(ToshibaProcessError);
  4020. } else {
  4021. // this is a problem!
  4022. // workaround by locking this twice, once for us and
  4023. // once for the non-existant locker from ScanForSpecial
  4024. ASSERT(!"hack flags show locked section, but none exists?");
  4025. locked = MmLockPagableCodeSection(CdRomRemoveDevice);
  4026. locked = MmLockPagableCodeSection(CdRomRemoveDevice);
  4027. }
  4028. MmUnlockPagableImageSection(locked);
  4029. MmUnlockPagableImageSection(locked);
  4030. }
  4031. //
  4032. // keep the system-wide count accurate, as
  4033. // programs use this info to know when they
  4034. // have found all the cdroms in a system.
  4035. //
  4036. TraceLog((CdromDebugTrace,
  4037. "CDROM.SYS Remove device\n"));
  4038. IoGetConfigurationInformation()->CdRomCount--;
  4039. }
  4040. //
  4041. // so long, and thanks for all the fish!
  4042. //
  4043. return STATUS_SUCCESS;
  4044. }
  4045. DEVICE_TYPE
  4046. CdRomGetDeviceType(
  4047. IN PDEVICE_OBJECT DeviceObject
  4048. )
  4049. /*++
  4050. Routine Description:
  4051. This routine figures out the real device type
  4052. by checking CDVD_CAPABILITIES_PAGE
  4053. Arguments:
  4054. DeviceObject -
  4055. Return Value:
  4056. FILE_DEVICE_CD_ROM or FILE_DEVICE_DVD
  4057. --*/
  4058. {
  4059. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
  4060. PCDROM_DATA cdromExtension;
  4061. ULONG bufLength;
  4062. SCSI_REQUEST_BLOCK srb;
  4063. PCDB cdb;
  4064. PMODE_PARAMETER_HEADER10 modePageHeader;
  4065. PCDVD_CAPABILITIES_PAGE capPage;
  4066. ULONG capPageOffset;
  4067. DEVICE_TYPE deviceType;
  4068. NTSTATUS status;
  4069. BOOLEAN use6Byte;
  4070. PAGED_CODE();
  4071. //
  4072. // NOTE: don't cache this until understand how it affects GetMediaTypes()
  4073. //
  4074. //
  4075. // default device type
  4076. //
  4077. deviceType = FILE_DEVICE_CD_ROM;
  4078. fdoExtension = DeviceObject->DeviceExtension;
  4079. cdromExtension = fdoExtension->CommonExtension.DriverData;
  4080. use6Byte = TEST_FLAG(cdromExtension->XAFlags, XA_USE_6_BYTE);
  4081. RtlZeroMemory(&srb, sizeof(srb));
  4082. cdb = (PCDB)srb.Cdb;
  4083. //
  4084. // Build the MODE SENSE CDB. The data returned will be kept in the
  4085. // device extension and used to set block size.
  4086. //
  4087. if (use6Byte) {
  4088. bufLength = sizeof(CDVD_CAPABILITIES_PAGE) +
  4089. sizeof(MODE_PARAMETER_HEADER);
  4090. capPageOffset = sizeof(MODE_PARAMETER_HEADER);
  4091. cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
  4092. cdb->MODE_SENSE.Dbd = 1;
  4093. cdb->MODE_SENSE.PageCode = MODE_PAGE_CAPABILITIES;
  4094. cdb->MODE_SENSE.AllocationLength = (UCHAR)bufLength;
  4095. srb.CdbLength = 6;
  4096. } else {
  4097. bufLength = sizeof(CDVD_CAPABILITIES_PAGE) +
  4098. sizeof(MODE_PARAMETER_HEADER10);
  4099. capPageOffset = sizeof(MODE_PARAMETER_HEADER10);
  4100. cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
  4101. cdb->MODE_SENSE10.Dbd = 1;
  4102. cdb->MODE_SENSE10.PageCode = MODE_PAGE_CAPABILITIES;
  4103. cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(bufLength >> 8);
  4104. cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(bufLength >> 0);
  4105. srb.CdbLength = 10;
  4106. }
  4107. //
  4108. // Set timeout value from device extension.
  4109. //
  4110. srb.TimeOutValue = fdoExtension->TimeOutValue;
  4111. modePageHeader = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  4112. bufLength,
  4113. CDROM_TAG_MODE_DATA);
  4114. if (modePageHeader) {
  4115. RtlZeroMemory(modePageHeader, bufLength);
  4116. status = ClassSendSrbSynchronous(
  4117. DeviceObject,
  4118. &srb,
  4119. modePageHeader,
  4120. bufLength,
  4121. FALSE);
  4122. if (NT_SUCCESS(status) ||
  4123. (status == STATUS_DATA_OVERRUN) ||
  4124. (status == STATUS_BUFFER_OVERFLOW)
  4125. ) {
  4126. capPage = (PCDVD_CAPABILITIES_PAGE) (((PUCHAR) modePageHeader) + capPageOffset);
  4127. if ((capPage->PageCode == MODE_PAGE_CAPABILITIES) &&
  4128. (capPage->DVDROMRead || capPage->DVDRRead ||
  4129. capPage->DVDRAMRead || capPage->DVDRWrite ||
  4130. capPage->DVDRAMWrite)) {
  4131. deviceType = FILE_DEVICE_DVD;
  4132. }
  4133. }
  4134. ExFreePool (modePageHeader);
  4135. }
  4136. return deviceType;
  4137. }
  4138. NTSTATUS
  4139. CdRomCreateWellKnownName(
  4140. IN PDEVICE_OBJECT DeviceObject
  4141. )
  4142. /*++
  4143. Routine Description:
  4144. This routine creates a symbolic link to the cdrom device object
  4145. under \dosdevices. The number of the cdrom device does not neccessarily
  4146. match between \dosdevices and \device, but usually will be the same.
  4147. Saves the buffer
  4148. Arguments:
  4149. DeviceObject -
  4150. Return Value:
  4151. NTSTATUS
  4152. --*/
  4153. {
  4154. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  4155. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  4156. PCDROM_DATA cdromData = commonExtension->DriverData;
  4157. UNICODE_STRING unicodeLinkName;
  4158. WCHAR wideLinkName[64];
  4159. PWCHAR savedName;
  4160. LONG cdromNumber = fdoExtension->DeviceNumber;
  4161. NTSTATUS status;
  4162. //
  4163. // if already linked, assert then return
  4164. //
  4165. if (cdromData->WellKnownName.Buffer != NULL) {
  4166. TraceLog((CdromDebugError,
  4167. "CdRomCreateWellKnownName: link already exists %p\n",
  4168. cdromData->WellKnownName.Buffer));
  4169. ASSERT(FALSE);
  4170. return STATUS_UNSUCCESSFUL;
  4171. }
  4172. //
  4173. // find an unused CdRomNN to link to
  4174. //
  4175. do {
  4176. swprintf(wideLinkName, L"\\DosDevices\\CdRom%d", cdromNumber);
  4177. RtlInitUnicodeString(&unicodeLinkName, wideLinkName);
  4178. status = IoCreateSymbolicLink(&unicodeLinkName,
  4179. &(commonExtension->DeviceName));
  4180. cdromNumber++;
  4181. } while((status == STATUS_OBJECT_NAME_COLLISION) ||
  4182. (status == STATUS_OBJECT_NAME_EXISTS));
  4183. if (!NT_SUCCESS(status)) {
  4184. TraceLog((CdromDebugWarning,
  4185. "CdRomCreateWellKnownName: Error %lx linking %wZ to "
  4186. "device %wZ\n",
  4187. status,
  4188. &unicodeLinkName,
  4189. &(commonExtension->DeviceName)));
  4190. return status;
  4191. }
  4192. TraceLog((CdromDebugWarning,
  4193. "CdRomCreateWellKnownName: successfully linked %wZ "
  4194. "to device %wZ\n",
  4195. &unicodeLinkName,
  4196. &(commonExtension->DeviceName)));
  4197. //
  4198. // Save away the symbolic link name in the driver data block. We need
  4199. // it so we can delete the link when the device is removed.
  4200. //
  4201. savedName = ExAllocatePoolWithTag(PagedPool,
  4202. unicodeLinkName.MaximumLength,
  4203. CDROM_TAG_STRINGS);
  4204. if (savedName == NULL) {
  4205. IoDeleteSymbolicLink(&unicodeLinkName);
  4206. return STATUS_INSUFFICIENT_RESOURCES;
  4207. }
  4208. RtlCopyMemory(savedName,
  4209. unicodeLinkName.Buffer,
  4210. unicodeLinkName.MaximumLength);
  4211. RtlInitUnicodeString(&(cdromData->WellKnownName), savedName);
  4212. //
  4213. // the name was saved and the link created
  4214. //
  4215. return STATUS_SUCCESS;
  4216. }
  4217. VOID
  4218. CdRomDeleteWellKnownName(
  4219. IN PDEVICE_OBJECT DeviceObject
  4220. )
  4221. {
  4222. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  4223. PCDROM_DATA cdromData = commonExtension->DriverData;
  4224. if(cdromData->WellKnownName.Buffer != NULL) {
  4225. IoDeleteSymbolicLink(&(cdromData->WellKnownName));
  4226. ExFreePool(cdromData->WellKnownName.Buffer);
  4227. cdromData->WellKnownName.Buffer = NULL;
  4228. cdromData->WellKnownName.Length = 0;
  4229. cdromData->WellKnownName.MaximumLength = 0;
  4230. }
  4231. return;
  4232. }
  4233. NTSTATUS
  4234. CdRomGetDeviceParameter (
  4235. IN PDEVICE_OBJECT Fdo,
  4236. IN PWSTR ParameterName,
  4237. IN OUT PULONG ParameterValue
  4238. )
  4239. /*++
  4240. Routine Description:
  4241. retrieve a devnode registry parameter
  4242. Arguments:
  4243. DeviceObject - Cdrom Device Object
  4244. ParameterName - parameter name to look up
  4245. ParameterValuse - default parameter value
  4246. Return Value:
  4247. NT Status
  4248. --*/
  4249. {
  4250. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  4251. NTSTATUS status;
  4252. HANDLE deviceParameterHandle;
  4253. RTL_QUERY_REGISTRY_TABLE queryTable[2];
  4254. ULONG defaultParameterValue;
  4255. PAGED_CODE();
  4256. //
  4257. // open the given parameter
  4258. //
  4259. status = IoOpenDeviceRegistryKey(fdoExtension->LowerPdo,
  4260. PLUGPLAY_REGKEY_DRIVER,
  4261. KEY_READ,
  4262. &deviceParameterHandle);
  4263. if(NT_SUCCESS(status)) {
  4264. RtlZeroMemory(queryTable, sizeof(queryTable));
  4265. defaultParameterValue = *ParameterValue;
  4266. queryTable->Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
  4267. queryTable->Name = ParameterName;
  4268. queryTable->EntryContext = ParameterValue;
  4269. queryTable->DefaultType = REG_NONE;
  4270. queryTable->DefaultData = NULL;
  4271. queryTable->DefaultLength = 0;
  4272. status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
  4273. (PWSTR) deviceParameterHandle,
  4274. queryTable,
  4275. NULL,
  4276. NULL);
  4277. if (!NT_SUCCESS(status)) {
  4278. *ParameterValue = defaultParameterValue;
  4279. }
  4280. //
  4281. // close what we open
  4282. //
  4283. ZwClose(deviceParameterHandle);
  4284. }
  4285. return status;
  4286. } // CdRomGetDeviceParameter
  4287. NTSTATUS
  4288. CdRomSetDeviceParameter (
  4289. IN PDEVICE_OBJECT Fdo,
  4290. IN PWSTR ParameterName,
  4291. IN ULONG ParameterValue
  4292. )
  4293. /*++
  4294. Routine Description:
  4295. save a devnode registry parameter
  4296. Arguments:
  4297. DeviceObject - Cdrom Device Object
  4298. ParameterName - parameter name
  4299. ParameterValuse - parameter value
  4300. Return Value:
  4301. NT Status
  4302. --*/
  4303. {
  4304. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  4305. NTSTATUS status;
  4306. HANDLE deviceParameterHandle;
  4307. PAGED_CODE();
  4308. //
  4309. // open the given parameter
  4310. //
  4311. status = IoOpenDeviceRegistryKey(fdoExtension->LowerPdo,
  4312. PLUGPLAY_REGKEY_DRIVER,
  4313. KEY_READ | KEY_WRITE,
  4314. &deviceParameterHandle);
  4315. if(NT_SUCCESS(status)) {
  4316. status = RtlWriteRegistryValue(
  4317. RTL_REGISTRY_HANDLE,
  4318. (PWSTR) deviceParameterHandle,
  4319. ParameterName,
  4320. REG_DWORD,
  4321. &ParameterValue,
  4322. sizeof (ParameterValue));
  4323. //
  4324. // close what we open
  4325. //
  4326. ZwClose(deviceParameterHandle);
  4327. }
  4328. return status;
  4329. } // CdromSetDeviceParameter
  4330. VOID
  4331. CdRomPickDvdRegion(
  4332. IN PDEVICE_OBJECT Fdo
  4333. )
  4334. /*++
  4335. Routine Description:
  4336. pick a default dvd region
  4337. Arguments:
  4338. DeviceObject - Cdrom Device Object
  4339. Return Value:
  4340. NT Status
  4341. --*/
  4342. {
  4343. PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
  4344. PCDROM_DATA cddata = (PCDROM_DATA)(commonExtension->DriverData);
  4345. //
  4346. // these five pointers all point to dvdReadStructure or part of
  4347. // its data, so don't deallocate them more than once!
  4348. //
  4349. PDVD_READ_STRUCTURE dvdReadStructure;
  4350. PDVD_COPY_PROTECT_KEY copyProtectKey;
  4351. PDVD_COPYRIGHT_DESCRIPTOR dvdCopyRight;
  4352. PDVD_RPC_KEY rpcKey;
  4353. PDVD_SET_RPC_KEY dvdRpcKey;
  4354. IO_STATUS_BLOCK ioStatus;
  4355. ULONG bufferLen;
  4356. UCHAR mediaRegion;
  4357. ULONG pickDvdRegion;
  4358. ULONG defaultDvdRegion;
  4359. ULONG dvdRegion;
  4360. PAGED_CODE();
  4361. if ((pickDvdRegion = InterlockedExchange(&cddata->PickDvdRegion, 0)) == 0) {
  4362. //
  4363. // it was non-zero, so either another thread will do this, or
  4364. // we no longer need to pick a region
  4365. //
  4366. return;
  4367. }
  4368. //
  4369. // short-circuit if license agreement violated
  4370. //
  4371. if (cddata->DvdRpc0LicenseFailure) {
  4372. TraceLog((CdromDebugWarning,
  4373. "DVD License failure. Refusing to pick a region\n"));
  4374. InterlockedExchange(&cddata->PickDvdRegion, 0);
  4375. return;
  4376. }
  4377. bufferLen = max(
  4378. max(sizeof(DVD_DESCRIPTOR_HEADER) +
  4379. sizeof(DVD_COPYRIGHT_DESCRIPTOR),
  4380. sizeof(DVD_READ_STRUCTURE)
  4381. ),
  4382. max(DVD_RPC_KEY_LENGTH,
  4383. DVD_SET_RPC_KEY_LENGTH
  4384. ),
  4385. );
  4386. dvdReadStructure = (PDVD_READ_STRUCTURE)
  4387. ExAllocatePoolWithTag(PagedPool, bufferLen, DVD_TAG_DVD_REGION);
  4388. if (dvdReadStructure == NULL) {
  4389. InterlockedExchange(&cddata->PickDvdRegion, pickDvdRegion);
  4390. return;
  4391. }
  4392. if (cddata->DvdRpc0Device && cddata->Rpc0RetryRegistryCallback) {
  4393. TraceLog((CdromDebugWarning,
  4394. "CdRomPickDvdRegion (%p): now retrying RPC0 callback\n",
  4395. Fdo));
  4396. //
  4397. // get the registry settings again
  4398. //
  4399. ioStatus.Status = CdRomGetRpc0Settings(Fdo);
  4400. if (ioStatus.Status == STATUS_LICENSE_VIOLATION) {
  4401. //
  4402. // if this is the returned error, then
  4403. // the routine should have set this!
  4404. //
  4405. ASSERT(cddata->DvdRpc0LicenseFailure);
  4406. cddata->DvdRpc0LicenseFailure = 1;
  4407. TraceLog((CdromDebugWarning,
  4408. "CdRomPickDvdRegion (%p): "
  4409. "setting to fail all dvd ioctls due to CSS licensing "
  4410. "failure.\n", Fdo));
  4411. pickDvdRegion = 0;
  4412. goto getout;
  4413. }
  4414. //
  4415. // get the device region, again
  4416. //
  4417. copyProtectKey = (PDVD_COPY_PROTECT_KEY)dvdReadStructure;
  4418. RtlZeroMemory(copyProtectKey, bufferLen);
  4419. copyProtectKey->KeyLength = DVD_RPC_KEY_LENGTH;
  4420. copyProtectKey->KeyType = DvdGetRpcKey;
  4421. //
  4422. // Build a request for READ_KEY
  4423. //
  4424. ClassSendDeviceIoControlSynchronous(
  4425. IOCTL_DVD_READ_KEY,
  4426. Fdo,
  4427. copyProtectKey,
  4428. DVD_RPC_KEY_LENGTH,
  4429. DVD_RPC_KEY_LENGTH,
  4430. FALSE,
  4431. &ioStatus);
  4432. if (!NT_SUCCESS(ioStatus.Status)) {
  4433. TraceLog((CdromDebugWarning,
  4434. "CdRomPickDvdRegion: Unable to get "
  4435. "device RPC data (%x)\n", ioStatus.Status));
  4436. pickDvdRegion = 0;
  4437. goto getout;
  4438. }
  4439. //
  4440. // now that we have gotten the device's RPC data,
  4441. // we have set the device extension to usable data.
  4442. // no need to call back into this section of code again
  4443. //
  4444. cddata->Rpc0RetryRegistryCallback = 0;
  4445. rpcKey = (PDVD_RPC_KEY) copyProtectKey->KeyData;
  4446. //
  4447. // TypeCode of zero means that no region has been set.
  4448. //
  4449. if (rpcKey->TypeCode != 0) {
  4450. TraceLog((CdromDebugWarning,
  4451. "CdRomPickDvdRegion (%p): DVD Region already "
  4452. "chosen\n", Fdo));
  4453. pickDvdRegion = 0;
  4454. goto getout;
  4455. }
  4456. TraceLog((CdromDebugWarning,
  4457. "CdRomPickDvdRegion (%p): must choose initial DVD "
  4458. " Region\n", Fdo));
  4459. }
  4460. copyProtectKey = (PDVD_COPY_PROTECT_KEY) dvdReadStructure;
  4461. dvdCopyRight = (PDVD_COPYRIGHT_DESCRIPTOR)
  4462. ((PDVD_DESCRIPTOR_HEADER) dvdReadStructure)->Data;
  4463. //
  4464. // get the media region
  4465. //
  4466. RtlZeroMemory (dvdReadStructure, bufferLen);
  4467. dvdReadStructure->Format = DvdCopyrightDescriptor;
  4468. //
  4469. // Build and send a request for READ_KEY
  4470. //
  4471. TraceLog((CdromDebugTrace,
  4472. "CdRomPickDvdRegion (%p): Getting Copyright Descriptor\n",
  4473. Fdo));
  4474. ClassSendDeviceIoControlSynchronous(
  4475. IOCTL_DVD_READ_STRUCTURE,
  4476. Fdo,
  4477. dvdReadStructure,
  4478. sizeof(DVD_READ_STRUCTURE),
  4479. sizeof (DVD_DESCRIPTOR_HEADER) +
  4480. sizeof(DVD_COPYRIGHT_DESCRIPTOR),
  4481. FALSE,
  4482. &ioStatus
  4483. );
  4484. TraceLog((CdromDebugTrace,
  4485. "CdRomPickDvdRegion (%p): Got Copyright Descriptor %x\n",
  4486. Fdo, ioStatus.Status));
  4487. if ((NT_SUCCESS(ioStatus.Status)) &&
  4488. (dvdCopyRight->CopyrightProtectionType == 0x01)
  4489. ) {
  4490. //
  4491. // keep the media region bitmap around
  4492. // a 1 means ok to play
  4493. //
  4494. if (dvdCopyRight->RegionManagementInformation == 0xff) {
  4495. TraceLog((CdromDebugError,
  4496. "CdRomPickDvdRegion (%p): RegionManagementInformation "
  4497. "is set to dis-allow playback for all regions. This is "
  4498. "most likely a poorly authored disc. defaulting to all "
  4499. "region disc for purpose of choosing initial region\n",
  4500. Fdo));
  4501. dvdCopyRight->RegionManagementInformation = 0;
  4502. }
  4503. mediaRegion = ~dvdCopyRight->RegionManagementInformation;
  4504. } else {
  4505. //
  4506. // could be media, can't set the device region
  4507. //
  4508. if (!cddata->DvdRpc0Device) {
  4509. //
  4510. // can't automatically pick a default region on a rpc2 drive
  4511. // without media, so just exit
  4512. //
  4513. TraceLog((CdromDebugWarning,
  4514. "CdRomPickDvdRegion (%p): failed to auto-choose "
  4515. "a region due to status %x getting copyright "
  4516. "descriptor\n", Fdo, ioStatus.Status));
  4517. goto getout;
  4518. } else {
  4519. //
  4520. // for an RPC0 drive, we can try to pick a region for
  4521. // the drive
  4522. //
  4523. mediaRegion = 0x0;
  4524. }
  4525. }
  4526. //
  4527. // get the device region
  4528. //
  4529. RtlZeroMemory (copyProtectKey, bufferLen);
  4530. copyProtectKey->KeyLength = DVD_RPC_KEY_LENGTH;
  4531. copyProtectKey->KeyType = DvdGetRpcKey;
  4532. //
  4533. // Build and send a request for READ_KEY for RPC key
  4534. //
  4535. TraceLog((CdromDebugTrace,
  4536. "CdRomPickDvdRegion (%p): Getting RpcKey\n",
  4537. Fdo));
  4538. ClassSendDeviceIoControlSynchronous(
  4539. IOCTL_DVD_READ_KEY,
  4540. Fdo,
  4541. copyProtectKey,
  4542. DVD_RPC_KEY_LENGTH,
  4543. DVD_RPC_KEY_LENGTH,
  4544. FALSE,
  4545. &ioStatus
  4546. );
  4547. TraceLog((CdromDebugTrace,
  4548. "CdRomPickDvdRegion (%p): Got RpcKey %x\n",
  4549. Fdo, ioStatus.Status));
  4550. if (!NT_SUCCESS(ioStatus.Status)) {
  4551. TraceLog((CdromDebugWarning,
  4552. "CdRomPickDvdRegion (%p): failed to get RpcKey from "
  4553. "a DVD Device\n", Fdo));
  4554. goto getout;
  4555. }
  4556. //
  4557. // so we now have what we can get for the media region and the
  4558. // drive region. we will not set a region if the drive has one
  4559. // set already (mask is not all 1's), nor will we set a region
  4560. // if there are no more user resets available.
  4561. //
  4562. rpcKey = (PDVD_RPC_KEY) copyProtectKey->KeyData;
  4563. if (rpcKey->RegionMask != 0xff) {
  4564. TraceLog((CdromDebugWarning,
  4565. "CdRomPickDvdRegion (%p): not picking a region since "
  4566. "it is already chosen\n", Fdo));
  4567. goto getout;
  4568. }
  4569. if (rpcKey->UserResetsAvailable <= 1) {
  4570. TraceLog((CdromDebugWarning,
  4571. "CdRomPickDvdRegion (%p): not picking a region since "
  4572. "only one change remains\n", Fdo));
  4573. goto getout;
  4574. }
  4575. defaultDvdRegion = 0;
  4576. //
  4577. // the proppage dvd class installer sets
  4578. // this key based upon the system locale
  4579. //
  4580. CdRomGetDeviceParameter (
  4581. Fdo,
  4582. DVD_DEFAULT_REGION,
  4583. &defaultDvdRegion
  4584. );
  4585. if (defaultDvdRegion > DVD_MAX_REGION) {
  4586. //
  4587. // the registry has a bogus default
  4588. //
  4589. TraceLog((CdromDebugWarning,
  4590. "CdRomPickDvdRegion (%p): registry has a bogus default "
  4591. "region value of %x\n", Fdo, defaultDvdRegion));
  4592. defaultDvdRegion = 0;
  4593. }
  4594. //
  4595. // if defaultDvdRegion == 0, it means no default.
  4596. //
  4597. //
  4598. // we will select the initial dvd region for the user
  4599. //
  4600. if ((defaultDvdRegion != 0) &&
  4601. (mediaRegion &
  4602. (1 << (defaultDvdRegion - 1))
  4603. )
  4604. ) {
  4605. //
  4606. // first choice:
  4607. // the media has region that matches
  4608. // the default dvd region.
  4609. //
  4610. dvdRegion = (1 << (defaultDvdRegion - 1));
  4611. TraceLog((CdromDebugWarning,
  4612. "CdRomPickDvdRegion (%p): Choice #1: media matches "
  4613. "drive's default, chose region %x\n", Fdo, dvdRegion));
  4614. } else if (mediaRegion) {
  4615. //
  4616. // second choice:
  4617. // pick the lowest region number
  4618. // from the media
  4619. //
  4620. UCHAR mask;
  4621. mask = 1;
  4622. dvdRegion = 0;
  4623. while (mediaRegion && !dvdRegion) {
  4624. //
  4625. // pick the lowest bit
  4626. //
  4627. dvdRegion = mediaRegion & mask;
  4628. mask <<= 1;
  4629. }
  4630. TraceLog((CdromDebugWarning,
  4631. "CdRomPickDvdRegion (%p): Choice #2: choosing lowest "
  4632. "media region %x\n", Fdo, dvdRegion));
  4633. } else if (defaultDvdRegion) {
  4634. //
  4635. // third choice:
  4636. // default dvd region from the dvd class installer
  4637. //
  4638. dvdRegion = (1 << (defaultDvdRegion - 1));
  4639. TraceLog((CdromDebugWarning,
  4640. "CdRomPickDvdRegion (%p): Choice #3: using default "
  4641. "region for this install %x\n", Fdo, dvdRegion));
  4642. } else {
  4643. //
  4644. // unable to pick one for the user -- this should rarely
  4645. // happen, since the proppage dvd class installer sets
  4646. // the key based upon the system locale
  4647. //
  4648. TraceLog((CdromDebugWarning,
  4649. "CdRomPickDvdRegion (%p): Choice #4: failed to choose "
  4650. "a media region\n", Fdo));
  4651. goto getout;
  4652. }
  4653. //
  4654. // now that we've chosen a region, set the region by sending the
  4655. // appropriate request to the drive
  4656. //
  4657. RtlZeroMemory (copyProtectKey, bufferLen);
  4658. copyProtectKey->KeyLength = DVD_SET_RPC_KEY_LENGTH;
  4659. copyProtectKey->KeyType = DvdSetRpcKey;
  4660. dvdRpcKey = (PDVD_SET_RPC_KEY) copyProtectKey->KeyData;
  4661. dvdRpcKey->PreferredDriveRegionCode = (UCHAR) ~dvdRegion;
  4662. //
  4663. // Build and send request for SEND_KEY
  4664. //
  4665. TraceLog((CdromDebugTrace,
  4666. "CdRomPickDvdRegion (%p): Sending new Rpc Key to region %x\n",
  4667. Fdo, dvdRegion));
  4668. ClassSendDeviceIoControlSynchronous(
  4669. IOCTL_DVD_SEND_KEY2,
  4670. Fdo,
  4671. copyProtectKey,
  4672. DVD_SET_RPC_KEY_LENGTH,
  4673. 0,
  4674. FALSE,
  4675. &ioStatus);
  4676. TraceLog((CdromDebugTrace,
  4677. "CdRomPickDvdRegion (%p): Sent new Rpc Key %x\n",
  4678. Fdo, ioStatus.Status));
  4679. if (!NT_SUCCESS(ioStatus.Status)) {
  4680. DebugPrint ((1, "CdRomPickDvdRegion (%p): unable to set dvd initial "
  4681. " region code (%p)\n", Fdo, ioStatus.Status));
  4682. } else {
  4683. DebugPrint ((1, "CdRomPickDvdRegion (%p): Successfully set dvd "
  4684. "initial region\n", Fdo));
  4685. pickDvdRegion = 0;
  4686. }
  4687. getout:
  4688. if (dvdReadStructure) {
  4689. ExFreePool (dvdReadStructure);
  4690. }
  4691. //
  4692. // update the new PickDvdRegion value
  4693. //
  4694. InterlockedExchange(&cddata->PickDvdRegion, pickDvdRegion);
  4695. return;
  4696. }
  4697. NTSTATUS
  4698. CdRomRetryRequest(
  4699. IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  4700. IN PIRP Irp,
  4701. IN ULONG Delay,
  4702. IN BOOLEAN ResendIrp
  4703. )
  4704. {
  4705. PCDROM_DATA cdData;
  4706. KIRQL oldIrql;
  4707. if(Delay == 0) {
  4708. return CdRomRerunRequest(FdoExtension, Irp, ResendIrp);
  4709. }
  4710. cdData = FdoExtension->CommonExtension.DriverData;
  4711. KeAcquireSpinLock(&(cdData->DelayedRetrySpinLock), &oldIrql);
  4712. ASSERT(cdData->DelayedRetryIrp == NULL);
  4713. ASSERT(cdData->DelayedRetryInterval == 0);
  4714. cdData->DelayedRetryIrp = Irp;
  4715. cdData->DelayedRetryInterval = Delay;
  4716. cdData->DelayedRetryResend = ResendIrp;
  4717. KeReleaseSpinLock(&(cdData->DelayedRetrySpinLock), oldIrql);
  4718. return STATUS_PENDING;
  4719. }
  4720. NTSTATUS
  4721. CdRomRerunRequest(
  4722. IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  4723. IN OPTIONAL PIRP Irp,
  4724. IN BOOLEAN ResendIrp
  4725. )
  4726. {
  4727. if(ResendIrp) {
  4728. return IoCallDriver(FdoExtension->CommonExtension.LowerDeviceObject,
  4729. Irp);
  4730. } else {
  4731. KIRQL oldIrql;
  4732. oldIrql = KeRaiseIrqlToDpcLevel();
  4733. CdRomStartIo(FdoExtension->DeviceObject, Irp);
  4734. KeLowerIrql(oldIrql);
  4735. return STATUS_MORE_PROCESSING_REQUIRED;
  4736. }
  4737. }
  4738. /*++
  4739. Routine Description:
  4740. This routine just checks for media change sense/asc/ascq and
  4741. also for other events, such as bus resets. this is used to
  4742. determine if the device behaviour has changed, to allow for
  4743. read and write operations to be allowed and/or disallowed.
  4744. Arguments:
  4745. ISSUE-2000/3/30-henrygab - not fully doc'd
  4746. Return Value:
  4747. NTSTATUS
  4748. --*/
  4749. NTSTATUS
  4750. CdRomMmcErrorHandler(
  4751. IN PDEVICE_OBJECT Fdo,
  4752. IN PSCSI_REQUEST_BLOCK Srb,
  4753. OUT PNTSTATUS Status,
  4754. OUT PBOOLEAN Retry
  4755. )
  4756. {
  4757. PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
  4758. BOOLEAN queryCapabilities = FALSE;
  4759. if (TEST_FLAG(Srb->SrbStatus, SRB_STATUS_AUTOSENSE_VALID)) {
  4760. PCDROM_DATA cddata = (PCDROM_DATA)commonExtension->DriverData;
  4761. PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer;
  4762. //
  4763. // the following sense keys could indicate a change in
  4764. // capabilities.
  4765. //
  4766. //
  4767. // we used to expect this to be serialized, and only hit from our
  4768. // own routine. we now allow some requests to continue during our
  4769. // processing of the capabilities update in order to allow
  4770. // IoReadPartitionTable() to succeed.
  4771. //
  4772. switch (senseBuffer->SenseKey & 0xf) {
  4773. case SCSI_SENSE_NOT_READY: {
  4774. if (senseBuffer->AdditionalSenseCode ==
  4775. SCSI_ADSENSE_NO_MEDIA_IN_DEVICE) {
  4776. if (cddata->Mmc.WriteAllowed) {
  4777. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  4778. "CdromErrorHandler: media removed, writes will be "
  4779. "failed until new media detected\n"));
  4780. }
  4781. // NOTE - REF #0002
  4782. cddata->Mmc.WriteAllowed = FALSE;
  4783. } else
  4784. if ((senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) &&
  4785. (senseBuffer->AdditionalSenseCodeQualifier ==
  4786. SCSI_SENSEQ_BECOMING_READY)) {
  4787. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  4788. "CdromErrorHandler: media becoming ready, "
  4789. "SHOULD notify shell of change time by sending "
  4790. "GESN request immediately!\n"));
  4791. }
  4792. break;
  4793. } // end SCSI_SENSE_NOT_READY
  4794. case SCSI_SENSE_UNIT_ATTENTION: {
  4795. switch (senseBuffer->AdditionalSenseCode) {
  4796. case SCSI_ADSENSE_MEDIUM_CHANGED: {
  4797. //
  4798. // always update if the medium may have changed
  4799. //
  4800. // NOTE - REF #0002
  4801. cddata->Mmc.WriteAllowed = FALSE;
  4802. InterlockedCompareExchange(&(cddata->Mmc.UpdateState),
  4803. CdromMmcUpdateRequired,
  4804. CdromMmcUpdateComplete);
  4805. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  4806. "CdromErrorHandler: media change detected, need to "
  4807. "update drive capabilities\n"));
  4808. break;
  4809. } // end SCSI_ADSENSE_MEDIUM_CHANGED
  4810. case SCSI_ADSENSE_BUS_RESET: {
  4811. // NOTE - REF #0002
  4812. cddata->Mmc.WriteAllowed = FALSE;
  4813. InterlockedCompareExchange(&(cddata->Mmc.UpdateState),
  4814. CdromMmcUpdateRequired,
  4815. CdromMmcUpdateComplete);
  4816. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  4817. "CdromErrorHandler: bus reset detected, need to "
  4818. "update drive capabilities\n"));
  4819. break;
  4820. } // end SCSI_ADSENSE_BUS_RESET
  4821. case SCSI_ADSENSE_OPERATOR_REQUEST: {
  4822. BOOLEAN b = FALSE;
  4823. switch (senseBuffer->AdditionalSenseCodeQualifier) {
  4824. case SCSI_SENSEQ_MEDIUM_REMOVAL: {
  4825. //
  4826. // eject notification currently handled by classpnp
  4827. //
  4828. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  4829. "CdromErrorHandler: Eject requested by user\n"));
  4830. *Retry = TRUE;
  4831. *Status = STATUS_DEVICE_BUSY;
  4832. break;
  4833. }
  4834. case SCSI_SENSEQ_WRITE_PROTECT_DISABLE:
  4835. b = TRUE;
  4836. case SCSI_SENSEQ_WRITE_PROTECT_ENABLE: {
  4837. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  4838. "CdromErrorHandler: Write protect %s requested "
  4839. "by user\n",
  4840. (b ? "disable" : "enable")));
  4841. *Retry = TRUE;
  4842. *Status = STATUS_DEVICE_BUSY;
  4843. // NOTE - REF #0002
  4844. cddata->Mmc.WriteAllowed = FALSE;
  4845. InterlockedCompareExchange(&(cddata->Mmc.UpdateState),
  4846. CdromMmcUpdateRequired,
  4847. CdromMmcUpdateComplete);
  4848. }
  4849. } // end of AdditionalSenseCodeQualifier switch
  4850. break;
  4851. } // end SCSI_ADSENSE_OPERATOR_REQUEST
  4852. default: {
  4853. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  4854. "CdromErrorHandler: Unit attention %02x/%02x\n",
  4855. senseBuffer->AdditionalSenseCode,
  4856. senseBuffer->AdditionalSenseCodeQualifier));
  4857. break;
  4858. }
  4859. } // end of AdditionSenseCode switch
  4860. break;
  4861. } // end SCSI_SENSE_UNIT_ATTENTION
  4862. case SCSI_SENSE_ILLEGAL_REQUEST: {
  4863. if (senseBuffer->AdditionalSenseCode ==
  4864. SCSI_ADSENSE_WRITE_PROTECT) {
  4865. if (cddata->Mmc.WriteAllowed) {
  4866. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  4867. "CdromErrorHandler: media was writable, but "
  4868. "failed request with WRITE_PROTECT error...\n"));
  4869. }
  4870. // NOTE - REF #0002
  4871. // do not update all the capabilities just because
  4872. // we can't write to the disc.
  4873. cddata->Mmc.WriteAllowed = FALSE;
  4874. }
  4875. break;
  4876. } // end SCSI_SENSE_ILLEGAL_REQUEST
  4877. } // end of SenseKey switch
  4878. } // end of SRB_STATUS_AUTOSENSE_VALID
  4879. return STATUS_SUCCESS;
  4880. }
  4881. /*++
  4882. Routine Description:
  4883. This routine checks for a device-specific error handler
  4884. and calls it if it exists. This allows multiple drives
  4885. that require their own error handler to co-exist.
  4886. --*/
  4887. VOID
  4888. CdRomErrorHandler(
  4889. PDEVICE_OBJECT DeviceObject,
  4890. PSCSI_REQUEST_BLOCK Srb,
  4891. NTSTATUS *Status,
  4892. BOOLEAN *Retry
  4893. )
  4894. {
  4895. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  4896. PCDROM_DATA cddata = (PCDROM_DATA)commonExtension->DriverData;
  4897. PSENSE_DATA sense = Srb->SenseInfoBuffer;
  4898. if ((Srb->SenseInfoBufferLength >=
  4899. RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA,AdditionalSenseCodeQualifier)) &&
  4900. TEST_FLAG(Srb->SrbStatus, SRB_STATUS_AUTOSENSE_VALID)) {
  4901. //
  4902. // Many non-WHQL certified drives (mostly CD-RW) return
  4903. // 2/4/0 when they have no media instead of the obvious
  4904. // choice of:
  4905. //
  4906. // SCSI_SENSE_NOT_READY/SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
  4907. //
  4908. // These drives should not pass WHQL certification due
  4909. // to this discrepency.
  4910. //
  4911. // However, we have to retry on 2/4/0 (Not ready, LUN not ready,
  4912. // no info) and also 3/2/0 (no seek complete).
  4913. //
  4914. // These conditions occur when the shell tries to examine an
  4915. // injected CD (e.g. for autoplay) before the CD is spun up.
  4916. //
  4917. // The drive should be returning an ASCQ of SCSI_SENSEQ_BECOMING_READY
  4918. // (0x01) in order to comply with WHQL standards.
  4919. //
  4920. // The default retry timeout of one second is acceptable to balance
  4921. // these discrepencies. don't modify the status, though....
  4922. //
  4923. if (((sense->SenseKey & 0xf) == SCSI_SENSE_NOT_READY) &&
  4924. (sense->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) &&
  4925. (sense->AdditionalSenseCodeQualifier == SCSI_SENSEQ_CAUSE_NOT_REPORTABLE)
  4926. ) {
  4927. *Retry = TRUE;
  4928. } else if (((sense->SenseKey & 0xf) == SCSI_SENSE_MEDIUM_ERROR) &&
  4929. (sense->AdditionalSenseCode == 0x2) &&
  4930. (sense->AdditionalSenseCodeQualifier == 0x0)
  4931. ) {
  4932. *Retry = TRUE;
  4933. } else if ((sense->AdditionalSenseCode == 0x57) &&
  4934. (sense->AdditionalSenseCodeQualifier == 0x00)
  4935. ) {
  4936. //
  4937. // UNABLE_TO_RECOVER_TABLE_OF_CONTENTS
  4938. // the Matshita CR-585 returns this for all read commands
  4939. // on blank CD-R and CD-RW media, and we need to handle
  4940. // this for READ_CD detection ability.
  4941. //
  4942. *Retry = FALSE;
  4943. *Status = STATUS_UNRECOGNIZED_MEDIA;
  4944. }
  4945. }
  4946. //
  4947. // tail recursion in both cases takes no stack
  4948. //
  4949. if (cddata->ErrorHandler) {
  4950. cddata->ErrorHandler(DeviceObject, Srb, Status, Retry);
  4951. }
  4952. return;
  4953. }
  4954. /*++
  4955. Routine Description:
  4956. This routine is called for a shutdown and flush IRPs.
  4957. These are sent by the system before it actually shuts
  4958. down or when the file system does a flush.
  4959. Arguments:
  4960. DriverObject - Pointer to device object to being shutdown by system.
  4961. Irp - IRP involved.
  4962. Return Value:
  4963. NT Status
  4964. --*/
  4965. NTSTATUS
  4966. CdRomShutdownFlush(
  4967. IN PDEVICE_OBJECT DeviceObject,
  4968. IN PIRP Irp
  4969. )
  4970. {
  4971. IoMarkIrpPending(Irp);
  4972. IoStartPacket(DeviceObject, Irp, NULL, NULL);
  4973. return STATUS_PENDING;
  4974. }
  4975. /*++
  4976. Routine Description:
  4977. This routine is called for intermediate work a shutdown or
  4978. flush IRPs would need to do. We just want to free our resources
  4979. and return STATUS_MORE_PROCESSING_REQUIRED.
  4980. Arguments:
  4981. DeviceObject - NULL?
  4982. Irp - IRP to free
  4983. Context - NULL
  4984. Return Value:
  4985. NT Status
  4986. --*/
  4987. NTSTATUS
  4988. CdRomShutdownFlushCompletion(
  4989. IN PDEVICE_OBJECT Fdo,
  4990. IN PIRP NewIrp,
  4991. IN PIRP OriginalIrp
  4992. )
  4993. {
  4994. PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
  4995. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  4996. PIO_STACK_LOCATION originalIrpStack;
  4997. ULONG_PTR iteration;
  4998. NTSTATUS status = STATUS_SUCCESS;
  4999. ASSERT(OriginalIrp);
  5000. originalIrpStack = IoGetCurrentIrpStackLocation(OriginalIrp);
  5001. //
  5002. // always use a new irp so we can call
  5003. // CdRomCompleteIrpAndStartNextPacketSafely() from this routine.
  5004. //
  5005. if (NewIrp != NULL) {
  5006. status = NewIrp->IoStatus.Status;
  5007. IoFreeIrp(NewIrp);
  5008. NewIrp = NULL;
  5009. }
  5010. if (!NT_SUCCESS(status)) {
  5011. BAIL_OUT(OriginalIrp);
  5012. goto SafeExit;
  5013. }
  5014. //
  5015. // the current irpstack saves the counter which states
  5016. // what part of the multi-part shutdown or flush we are in.
  5017. //
  5018. iteration = (ULONG_PTR)originalIrpStack->Parameters.Others.Argument1;
  5019. iteration++;
  5020. originalIrpStack->Parameters.Others.Argument1 = (PVOID)iteration;
  5021. switch (iteration) {
  5022. case 2:
  5023. if (originalIrpStack->MajorFunction != IRP_MJ_SHUTDOWN) {
  5024. //
  5025. // then we don't want to send the unlock command
  5026. // the incrementing of the state was done above.
  5027. // return the completion routine's result.
  5028. //
  5029. return CdRomShutdownFlushCompletion(Fdo, NULL, OriginalIrp);
  5030. }
  5031. // else fall through....
  5032. case 1: {
  5033. PIRP newIrp = NULL;
  5034. PSCSI_REQUEST_BLOCK newSrb = NULL;
  5035. PCDB newCdb = NULL;
  5036. PIO_STACK_LOCATION newIrpStack = NULL;
  5037. ULONG isRemoved;
  5038. newIrp = IoAllocateIrp((CCHAR)(Fdo->StackSize+1), FALSE);
  5039. if (newIrp == NULL) {
  5040. BAIL_OUT(OriginalIrp);
  5041. status = STATUS_INSUFFICIENT_RESOURCES;
  5042. goto SafeExit;
  5043. }
  5044. newSrb = ExAllocatePoolWithTag(NonPagedPool,
  5045. sizeof(SCSI_REQUEST_BLOCK),
  5046. CDROM_TAG_SRB);
  5047. if (newSrb == NULL) {
  5048. IoFreeIrp(newIrp);
  5049. BAIL_OUT(OriginalIrp);
  5050. status = STATUS_INSUFFICIENT_RESOURCES;
  5051. goto SafeExit;
  5052. }
  5053. //
  5054. // ClassIoComplete will free the SRB, but we need a routine
  5055. // that will free the irp. then just call ClassSendAsync,
  5056. // and don't care about the return value, since the completion
  5057. // routine will be called anyways.
  5058. //
  5059. IoSetNextIrpStackLocation(newIrp);
  5060. newIrpStack = IoGetCurrentIrpStackLocation(newIrp);
  5061. newIrpStack->DeviceObject = Fdo;
  5062. IoSetCompletionRoutine(newIrp,
  5063. CdRomShutdownFlushCompletion,
  5064. OriginalIrp,
  5065. TRUE, TRUE, TRUE);
  5066. IoSetNextIrpStackLocation(newIrp);
  5067. newIrpStack = IoGetCurrentIrpStackLocation(newIrp);
  5068. newIrpStack->DeviceObject = Fdo;
  5069. //
  5070. // setup the request
  5071. //
  5072. RtlZeroMemory(newSrb, sizeof(SCSI_REQUEST_BLOCK));
  5073. newCdb = (PCDB)(newSrb->Cdb);
  5074. newSrb->QueueTag = SP_UNTAGGED;
  5075. newSrb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
  5076. newSrb->Function = SRB_FUNCTION_EXECUTE_SCSI;
  5077. //
  5078. // tell classpnp not to call StartNextPacket()
  5079. //
  5080. newSrb->SrbFlags = SRB_FLAGS_DONT_START_NEXT_PACKET;
  5081. if (iteration == 1) {
  5082. //
  5083. // first synchronize the cache
  5084. //
  5085. newSrb->TimeOutValue = fdoExtension->TimeOutValue * 4;
  5086. newSrb->CdbLength = 10;
  5087. newCdb->SYNCHRONIZE_CACHE10.OperationCode = SCSIOP_SYNCHRONIZE_CACHE;
  5088. } else if (iteration == 2) {
  5089. //
  5090. // then unlock the medium
  5091. //
  5092. ASSERT( originalIrpStack->MajorFunction == IRP_MJ_SHUTDOWN );
  5093. newSrb->TimeOutValue = fdoExtension->TimeOutValue;
  5094. newSrb->CdbLength = 6;
  5095. newCdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
  5096. newCdb->MEDIA_REMOVAL.Prevent = FALSE;
  5097. }
  5098. isRemoved = ClassAcquireRemoveLock(Fdo, newIrp);
  5099. if (isRemoved) {
  5100. IoFreeIrp(newIrp);
  5101. ExFreePool(newSrb);
  5102. ClassReleaseRemoveLock(Fdo, newIrp);
  5103. BAIL_OUT(OriginalIrp);
  5104. status = STATUS_DEVICE_DOES_NOT_EXIST;
  5105. goto SafeExit;
  5106. }
  5107. ClassSendSrbAsynchronous(Fdo, newSrb, newIrp, NULL, 0, FALSE);
  5108. break;
  5109. }
  5110. case 3: {
  5111. PSCSI_REQUEST_BLOCK srb;
  5112. PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(OriginalIrp);
  5113. //
  5114. // forward this request to the device appropriately,
  5115. // don't use this completion routine anymore...
  5116. //
  5117. srb = ExAllocatePoolWithTag(NonPagedPool,
  5118. sizeof(SCSI_REQUEST_BLOCK),
  5119. CDROM_TAG_SRB);
  5120. if (srb == NULL) {
  5121. BAIL_OUT(OriginalIrp);
  5122. status = STATUS_INSUFFICIENT_RESOURCES;
  5123. goto SafeExit;
  5124. }
  5125. RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
  5126. srb->Length = SCSI_REQUEST_BLOCK_SIZE;
  5127. srb->TimeOutValue = fdoExtension->TimeOutValue * 4;
  5128. srb->QueueTag = SP_UNTAGGED;
  5129. srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
  5130. srb->SrbFlags = fdoExtension->SrbFlags;
  5131. srb->CdbLength = 0;
  5132. srb->OriginalRequest = OriginalIrp;
  5133. if (originalIrpStack->MajorFunction == IRP_MJ_SHUTDOWN) {
  5134. srb->Function = SRB_FUNCTION_SHUTDOWN;
  5135. } else {
  5136. srb->Function = SRB_FUNCTION_FLUSH;
  5137. }
  5138. //
  5139. // Set up IoCompletion routine address.
  5140. //
  5141. IoSetCompletionRoutine(OriginalIrp,
  5142. ClassIoComplete,
  5143. srb,
  5144. TRUE, TRUE, TRUE);
  5145. //
  5146. // Set the retry count to zero.
  5147. //
  5148. originalIrpStack->Parameters.Others.Argument4 = (PVOID) 0;
  5149. //
  5150. // Get next stack location and set major function code.
  5151. //
  5152. nextIrpStack->MajorFunction = IRP_MJ_SCSI;
  5153. //
  5154. // Set up SRB for execute scsi request.
  5155. // Save SRB address in next stack for port driver.
  5156. //
  5157. nextIrpStack->Parameters.Scsi.Srb = srb;
  5158. //
  5159. // Call the port driver to process the request.
  5160. //
  5161. IoCallDriver(commonExtension->LowerDeviceObject, OriginalIrp);
  5162. break;
  5163. }
  5164. default: {
  5165. ASSERT(FALSE);
  5166. break;
  5167. }
  5168. } // end switch
  5169. status = STATUS_SUCCESS;
  5170. SafeExit:
  5171. if (!NT_SUCCESS(status)) {
  5172. OriginalIrp->IoStatus.Status = status;
  5173. CdRomCompleteIrpAndStartNextPacketSafely(Fdo, OriginalIrp);
  5174. }
  5175. //
  5176. // always return STATUS_MORE_PROCESSING_REQUIRED, so noone else tries
  5177. // to access the new irp that we free'd....
  5178. //
  5179. return STATUS_MORE_PROCESSING_REQUIRED;
  5180. } // end CdromShutdownFlush()
  5181. VOID
  5182. CdromFakePartitionInfo(
  5183. IN PCOMMON_DEVICE_EXTENSION CommonExtension,
  5184. IN PIRP Irp
  5185. )
  5186. {
  5187. PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
  5188. ULONG ioctl = currentIrpStack->Parameters.DeviceIoControl.IoControlCode;
  5189. PVOID systemBuffer = Irp->AssociatedIrp.SystemBuffer;
  5190. ASSERT(systemBuffer);
  5191. if ((ioctl != IOCTL_DISK_GET_DRIVE_LAYOUT) &&
  5192. (ioctl != IOCTL_DISK_GET_DRIVE_LAYOUT_EX) &&
  5193. (ioctl != IOCTL_DISK_GET_PARTITION_INFO) &&
  5194. (ioctl != IOCTL_DISK_GET_PARTITION_INFO_EX)) {
  5195. TraceLog((CdromDebugError,
  5196. "CdromFakePartitionInfo: unhandled ioctl %x\n", ioctl));
  5197. Irp->IoStatus.Status = STATUS_INTERNAL_ERROR;
  5198. Irp->IoStatus.Information = 0;
  5199. CdRomCompleteIrpAndStartNextPacketSafely(CommonExtension->DeviceObject,
  5200. Irp);
  5201. return;
  5202. }
  5203. //
  5204. // nothing to fail from this point on, so set the size appropriately
  5205. // and set irp's status to success.
  5206. //
  5207. TraceLog((CdromDebugWarning,
  5208. "CdromFakePartitionInfo: incoming ioctl %x\n", ioctl));
  5209. Irp->IoStatus.Status = STATUS_SUCCESS;
  5210. switch (ioctl) {
  5211. case IOCTL_DISK_GET_DRIVE_LAYOUT:
  5212. Irp->IoStatus.Information = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION,
  5213. PartitionEntry[1]);
  5214. RtlZeroMemory(systemBuffer, FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION,
  5215. PartitionEntry[1]));
  5216. break;
  5217. case IOCTL_DISK_GET_DRIVE_LAYOUT_EX:
  5218. Irp->IoStatus.Information = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX,
  5219. PartitionEntry[1]);
  5220. RtlZeroMemory(systemBuffer, FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX,
  5221. PartitionEntry[1]));
  5222. break;
  5223. case IOCTL_DISK_GET_PARTITION_INFO:
  5224. Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);
  5225. RtlZeroMemory(systemBuffer, sizeof(PARTITION_INFORMATION));
  5226. break;
  5227. case IOCTL_DISK_GET_PARTITION_INFO_EX:
  5228. Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION_EX);
  5229. RtlZeroMemory(systemBuffer, sizeof(PARTITION_INFORMATION_EX));
  5230. break;
  5231. default:
  5232. ASSERT(!"Invalid ioctl should not have reached this point\n");
  5233. break;
  5234. }
  5235. //
  5236. // if we are getting the drive layout, then we need to start by
  5237. // adding some of the non-partition stuff that says we have
  5238. // exactly one partition available.
  5239. //
  5240. if (ioctl == IOCTL_DISK_GET_DRIVE_LAYOUT) {
  5241. PDRIVE_LAYOUT_INFORMATION layout;
  5242. layout = (PDRIVE_LAYOUT_INFORMATION)systemBuffer;
  5243. layout->PartitionCount = 1;
  5244. layout->Signature = 1;
  5245. systemBuffer = (PVOID)(layout->PartitionEntry);
  5246. ioctl = IOCTL_DISK_GET_PARTITION_INFO;
  5247. } else if (ioctl == IOCTL_DISK_GET_DRIVE_LAYOUT_EX) {
  5248. PDRIVE_LAYOUT_INFORMATION_EX layoutEx;
  5249. layoutEx = (PDRIVE_LAYOUT_INFORMATION_EX)systemBuffer;
  5250. layoutEx->PartitionStyle = PARTITION_STYLE_MBR;
  5251. layoutEx->PartitionCount = 1;
  5252. layoutEx->Mbr.Signature = 1;
  5253. systemBuffer = (PVOID)(layoutEx->PartitionEntry);
  5254. ioctl = IOCTL_DISK_GET_PARTITION_INFO_EX;
  5255. }
  5256. //
  5257. // NOTE: the local var 'ioctl' is now modified to either EX or
  5258. // non-EX version. the local var 'systemBuffer' is now pointing
  5259. // to the partition information structure.
  5260. //
  5261. if (ioctl == IOCTL_DISK_GET_PARTITION_INFO) {
  5262. PPARTITION_INFORMATION partitionInfo;
  5263. partitionInfo = (PPARTITION_INFORMATION)systemBuffer;
  5264. partitionInfo->RewritePartition = FALSE;
  5265. partitionInfo->RecognizedPartition = TRUE;
  5266. partitionInfo->PartitionType = PARTITION_FAT32;
  5267. partitionInfo->BootIndicator = FALSE;
  5268. partitionInfo->HiddenSectors = 0;
  5269. partitionInfo->StartingOffset.QuadPart = 0;
  5270. partitionInfo->PartitionLength = CommonExtension->PartitionLength;
  5271. partitionInfo->PartitionNumber = 0;
  5272. } else {
  5273. PPARTITION_INFORMATION_EX partitionInfo;
  5274. partitionInfo = (PPARTITION_INFORMATION_EX)systemBuffer;
  5275. partitionInfo->PartitionStyle = PARTITION_STYLE_MBR;
  5276. partitionInfo->RewritePartition = FALSE;
  5277. partitionInfo->Mbr.RecognizedPartition = TRUE;
  5278. partitionInfo->Mbr.PartitionType = PARTITION_FAT32;
  5279. partitionInfo->Mbr.BootIndicator = FALSE;
  5280. partitionInfo->Mbr.HiddenSectors = 0;
  5281. partitionInfo->StartingOffset.QuadPart = 0;
  5282. partitionInfo->PartitionLength = CommonExtension->PartitionLength;
  5283. partitionInfo->PartitionNumber = 0;
  5284. }
  5285. TraceLog((CdromDebugWarning,
  5286. "CdromFakePartitionInfo: finishing ioctl %x\n",
  5287. currentIrpStack->Parameters.DeviceIoControl.IoControlCode));
  5288. //
  5289. // complete the irp
  5290. //
  5291. CdRomCompleteIrpAndStartNextPacketSafely(CommonExtension->DeviceObject,
  5292. Irp);
  5293. return;
  5294. }