Leaked source code of windows server 2003
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.

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