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.

4080 lines
127 KiB

  1. /*--
  2. Copyright (C) Microsoft Corporation, 1999 - 1999
  3. Module Name:
  4. ioctl.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 "ioctl.tmh"
  24. #if DBG
  25. PUCHAR READ_DVD_STRUCTURE_FORMAT_STRINGS[DvdMaxDescriptor+1] = {
  26. "Physical",
  27. "Copyright",
  28. "DiskKey",
  29. "BCA",
  30. "Manufacturer",
  31. "Unknown"
  32. };
  33. #endif // DBG
  34. #define DEFAULT_CDROM_SECTORS_PER_TRACK 32
  35. #define DEFAULT_TRACKS_PER_CYLINDER 64
  36. NTSTATUS
  37. CdRomDeviceControlDispatch(
  38. IN PDEVICE_OBJECT DeviceObject,
  39. IN PIRP Irp
  40. )
  41. /*++
  42. Routine Description:
  43. This is the NT device control handler for CDROMs.
  44. Arguments:
  45. DeviceObject - for this CDROM
  46. Irp - IO Request packet
  47. Return Value:
  48. NTSTATUS
  49. --*/
  50. {
  51. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  52. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  53. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  54. PIO_STACK_LOCATION nextStack;
  55. PCDROM_DATA cdData = (PCDROM_DATA)(commonExtension->DriverData);
  56. BOOLEAN use6Byte = TEST_FLAG(cdData->XAFlags, XA_USE_6_BYTE);
  57. SCSI_REQUEST_BLOCK srb = {0};
  58. PCDB cdb = (PCDB)srb.Cdb;
  59. PVOID outputBuffer;
  60. ULONG bytesTransferred = 0;
  61. NTSTATUS status;
  62. NTSTATUS status2;
  63. KIRQL irql;
  64. ULONG ioctlCode;
  65. ULONG baseCode;
  66. ULONG functionCode;
  67. RetryControl:
  68. //
  69. // Zero the SRB on stack.
  70. //
  71. RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
  72. Irp->IoStatus.Information = 0;
  73. //
  74. // if this is a class driver ioctl then we need to change the base code
  75. // to IOCTL_CDROM_BASE so that the switch statement can handle it.
  76. //
  77. // WARNING - currently the scsi class ioctl function codes are between
  78. // 0x200 & 0x300. this routine depends on that fact
  79. //
  80. ioctlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
  81. baseCode = ioctlCode >> 16;
  82. functionCode = (ioctlCode & (~0xffffc003)) >> 2;
  83. TraceLog((CdromDebugTrace,
  84. "CdRomDeviceControl: Ioctl Code = %lx, Base Code = %lx,"
  85. " Function Code = %lx\n",
  86. ioctlCode,
  87. baseCode,
  88. functionCode
  89. ));
  90. if((functionCode >= 0x200) && (functionCode <= 0x300)) {
  91. ioctlCode = (ioctlCode & 0x0000ffff) | CTL_CODE(IOCTL_CDROM_BASE, 0, 0, 0);
  92. TraceLog((CdromDebugTrace,
  93. "CdRomDeviceControl: Class Code - new ioctl code is %lx\n",
  94. ioctlCode));
  95. irpStack->Parameters.DeviceIoControl.IoControlCode = ioctlCode;
  96. }
  97. switch (ioctlCode) {
  98. case IOCTL_STORAGE_GET_MEDIA_TYPES_EX: {
  99. PGET_MEDIA_TYPES mediaTypes = Irp->AssociatedIrp.SystemBuffer;
  100. PDEVICE_MEDIA_INFO mediaInfo = &mediaTypes->MediaInfo[0];
  101. ULONG sizeNeeded;
  102. sizeNeeded = sizeof(GET_MEDIA_TYPES);
  103. //
  104. // IsMmc is static...
  105. //
  106. if (cdData->Mmc.IsMmc) {
  107. sizeNeeded += sizeof(DEVICE_MEDIA_INFO) * 1; // return two media types
  108. }
  109. //
  110. // Ensure that buffer is large enough.
  111. //
  112. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  113. sizeNeeded) {
  114. //
  115. // Buffer too small.
  116. //
  117. Irp->IoStatus.Information = sizeNeeded;
  118. status = STATUS_BUFFER_TOO_SMALL;
  119. break;
  120. }
  121. RtlZeroMemory(Irp->AssociatedIrp.SystemBuffer, sizeNeeded);
  122. //
  123. // ISSUE-2000/5/11-henrygab - need to update GET_MEDIA_TYPES_EX
  124. //
  125. mediaTypes->DeviceType = CdRomGetDeviceType(DeviceObject);
  126. mediaTypes->MediaInfoCount = 1;
  127. mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType = CD_ROM;
  128. mediaInfo->DeviceSpecific.RemovableDiskInfo.NumberMediaSides = 1;
  129. mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = MEDIA_READ_ONLY;
  130. mediaInfo->DeviceSpecific.RemovableDiskInfo.Cylinders.QuadPart = fdoExtension->DiskGeometry.Cylinders.QuadPart;
  131. mediaInfo->DeviceSpecific.RemovableDiskInfo.TracksPerCylinder = fdoExtension->DiskGeometry.TracksPerCylinder;
  132. mediaInfo->DeviceSpecific.RemovableDiskInfo.SectorsPerTrack = fdoExtension->DiskGeometry.SectorsPerTrack;
  133. mediaInfo->DeviceSpecific.RemovableDiskInfo.BytesPerSector = fdoExtension->DiskGeometry.BytesPerSector;
  134. if (cdData->Mmc.IsMmc) {
  135. //
  136. // also report a removable disk
  137. //
  138. mediaTypes->MediaInfoCount += 1;
  139. mediaInfo++;
  140. mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType = RemovableMedia;
  141. mediaInfo->DeviceSpecific.RemovableDiskInfo.NumberMediaSides = 1;
  142. mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = MEDIA_READ_WRITE;
  143. mediaInfo->DeviceSpecific.RemovableDiskInfo.Cylinders.QuadPart = fdoExtension->DiskGeometry.Cylinders.QuadPart;
  144. mediaInfo->DeviceSpecific.RemovableDiskInfo.TracksPerCylinder = fdoExtension->DiskGeometry.TracksPerCylinder;
  145. mediaInfo->DeviceSpecific.RemovableDiskInfo.SectorsPerTrack = fdoExtension->DiskGeometry.SectorsPerTrack;
  146. mediaInfo->DeviceSpecific.RemovableDiskInfo.BytesPerSector = fdoExtension->DiskGeometry.BytesPerSector;
  147. mediaInfo--;
  148. }
  149. //
  150. // Status will either be success, if media is present, or no media.
  151. // It would be optimal to base from density code and medium type, but not all devices
  152. // have values for these fields.
  153. //
  154. //
  155. // Send a TUR to determine if media is present.
  156. //
  157. srb.CdbLength = 6;
  158. cdb = (PCDB)srb.Cdb;
  159. cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
  160. //
  161. // Set timeout value.
  162. //
  163. srb.TimeOutValue = fdoExtension->TimeOutValue;
  164. status = ClassSendSrbSynchronous(DeviceObject,
  165. &srb,
  166. NULL,
  167. 0,
  168. FALSE);
  169. TraceLog((CdromDebugWarning,
  170. "CdRomDeviceControl: GET_MEDIA_TYPES status of TUR - %lx\n",
  171. status));
  172. if (NT_SUCCESS(status)) {
  173. //
  174. // set the disk's media as current if we can write to it.
  175. //
  176. if (cdData->Mmc.IsMmc && cdData->Mmc.WriteAllowed) {
  177. mediaInfo++;
  178. SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics,
  179. MEDIA_CURRENTLY_MOUNTED);
  180. mediaInfo--;
  181. } else {
  182. SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics,
  183. MEDIA_CURRENTLY_MOUNTED);
  184. }
  185. }
  186. Irp->IoStatus.Information = sizeNeeded;
  187. status = STATUS_SUCCESS;
  188. break;
  189. }
  190. case IOCTL_CDROM_RAW_READ: {
  191. LARGE_INTEGER startingOffset = {0};
  192. ULONGLONG transferBytes;
  193. ULONGLONG endOffset;
  194. ULONGLONG mdlBytes;
  195. ULONG startingSector;
  196. RAW_READ_INFO rawReadInfo;
  197. //
  198. // Ensure that XA reads are supported.
  199. //
  200. if (TEST_FLAG(cdData->XAFlags, XA_NOT_SUPPORTED)) {
  201. TraceLog((CdromDebugWarning,
  202. "CdRomDeviceControl: XA Reads not supported. Flags (%x)\n",
  203. cdData->XAFlags));
  204. status = STATUS_INVALID_DEVICE_REQUEST;
  205. break;
  206. }
  207. //
  208. // Check that ending sector is on disc and buffers are there and of
  209. // correct size.
  210. //
  211. if (!irpStack->Parameters.DeviceIoControl.Type3InputBuffer){
  212. /*
  213. * This is a call from user space. This is the only time that we need to validate parameters.
  214. * Validate the input and get the input buffer into Type3InputBuffer
  215. * so the rest of the code will be uniform.
  216. */
  217. if (Irp->AssociatedIrp.SystemBuffer){
  218. irpStack->Parameters.DeviceIoControl.Type3InputBuffer = Irp->AssociatedIrp.SystemBuffer;
  219. if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(RAW_READ_INFO)){
  220. status = STATUS_BUFFER_TOO_SMALL;
  221. break;
  222. }
  223. }
  224. else {
  225. status = STATUS_INVALID_PARAMETER;
  226. break;
  227. }
  228. }
  229. /*
  230. * Since this ioctl is METHOD_OUT_DIRECT, we need to copy away the input buffer before interpreting it.
  231. * This prevents a malicious app from messing with the input buffer while we are interpreting it.
  232. */
  233. rawReadInfo = *(PRAW_READ_INFO)irpStack->Parameters.DeviceIoControl.Type3InputBuffer;
  234. startingOffset.QuadPart = rawReadInfo.DiskOffset.QuadPart;
  235. startingSector = (ULONG)(rawReadInfo.DiskOffset.QuadPart >> fdoExtension->SectorShift);
  236. transferBytes = (ULONGLONG)rawReadInfo.SectorCount * RAW_SECTOR_SIZE;
  237. endOffset = (ULONGLONG)rawReadInfo.SectorCount * COOKED_SECTOR_SIZE;
  238. endOffset += startingOffset.QuadPart;
  239. //
  240. // check for overflows....
  241. //
  242. if (rawReadInfo.SectorCount == 0) {
  243. TraceLog((CdromDebugWarning,
  244. "CdRomDeviceControl: Invalid I/O parameters for XA "
  245. "Read (zero sectors requested)\n"));
  246. status = STATUS_INVALID_PARAMETER;
  247. break;
  248. }
  249. if (transferBytes < (ULONGLONG)(rawReadInfo.SectorCount)) {
  250. TraceLog((CdromDebugWarning,
  251. "CdRomDeviceControl: Invalid I/O parameters for XA "
  252. "Read (TransferBytes Overflow)\n"));
  253. status = STATUS_INVALID_PARAMETER;
  254. break;
  255. }
  256. if (endOffset < (ULONGLONG)startingOffset.QuadPart) {
  257. TraceLog((CdromDebugWarning,
  258. "CdRomDeviceControl: Invalid I/O parameters for XA "
  259. "Read (EndingOffset Overflow)\n"));
  260. status = STATUS_INVALID_PARAMETER;
  261. break;
  262. }
  263. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  264. transferBytes) {
  265. TraceLog((CdromDebugWarning,
  266. "CdRomDeviceControl: Invalid I/O parameters for XA "
  267. "Read (Bad buffer size)\n"));
  268. status = STATUS_INVALID_PARAMETER;
  269. break;
  270. }
  271. if (endOffset > (ULONGLONG)commonExtension->PartitionLength.QuadPart) {
  272. TraceLog((CdromDebugWarning,
  273. "CdRomDeviceControl: Invalid I/O parameters for XA "
  274. "Read (Request Out of Bounds)\n"));
  275. status = STATUS_INVALID_PARAMETER;
  276. break;
  277. }
  278. //
  279. // cannot validate the MdlAddress, since it is not included in any
  280. // other location per the DDK and file system calls.
  281. //
  282. //
  283. // validate the mdl describes at least the number of bytes
  284. // requested from us.
  285. //
  286. mdlBytes = (ULONGLONG)MmGetMdlByteCount(Irp->MdlAddress);
  287. if (mdlBytes < transferBytes) {
  288. TraceLog((CdromDebugWarning,
  289. "CdRomDeviceControl: Invalid MDL %s, Irp %p\n",
  290. "size (5)", Irp));
  291. status = STATUS_INVALID_PARAMETER;
  292. break;
  293. }
  294. //
  295. // check the buffer for alignment
  296. // This is important for x86 as some busses (ie ATAPI)
  297. // require word-aligned buffers.
  298. //
  299. if ( ((ULONG_PTR)MmGetMdlVirtualAddress(Irp->MdlAddress)) &
  300. fdoExtension->AdapterDescriptor->AlignmentMask
  301. )
  302. {
  303. TraceLog((CdromDebugWarning,
  304. "CdRomDeviceControl: Invalid I/O parameters for "
  305. "XA Read (Buffer %p not aligned with mask %x\n",
  306. irpStack->Parameters.DeviceIoControl.Type3InputBuffer,
  307. fdoExtension->AdapterDescriptor->AlignmentMask));
  308. status = STATUS_INVALID_PARAMETER;
  309. break;
  310. }
  311. //
  312. // HACKHACK - REF #0001
  313. // The retry count will be in this irp's IRP_MN function,
  314. // as the new irp was freed, and we therefore cannot use
  315. // this irp's next stack location for this function.
  316. // This may be a good location to store this info for
  317. // when we remove RAW_READ (mode switching), as we will
  318. // no longer have the nextIrpStackLocation to play with
  319. // when that occurs
  320. //
  321. // once XA_READ is removed, then this hack can also be
  322. // removed.
  323. //
  324. irpStack->MinorFunction = MAXIMUM_RETRIES; // HACKHACK - REF #0001
  325. IoMarkIrpPending(Irp);
  326. IoStartPacket(DeviceObject, Irp, NULL, NULL);
  327. return STATUS_PENDING;
  328. }
  329. case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX:
  330. case IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX: {
  331. TraceLog((CdromDebugTrace,
  332. "CdRomDeviceControl: Get drive geometryEx\n"));
  333. if ( irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  334. FIELD_OFFSET(DISK_GEOMETRY_EX, Data)) {
  335. status = STATUS_BUFFER_TOO_SMALL;
  336. Irp->IoStatus.Information = FIELD_OFFSET(DISK_GEOMETRY_EX, Data);
  337. break;
  338. }
  339. IoMarkIrpPending(Irp);
  340. IoStartPacket(DeviceObject, Irp, NULL, NULL);
  341. return STATUS_PENDING;
  342. }
  343. case IOCTL_DISK_GET_DRIVE_GEOMETRY:
  344. case IOCTL_CDROM_GET_DRIVE_GEOMETRY: {
  345. TraceLog((CdromDebugTrace,
  346. "CdRomDeviceControl: Get drive geometry\n"));
  347. if ( irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  348. sizeof( DISK_GEOMETRY ) ) {
  349. status = STATUS_BUFFER_TOO_SMALL;
  350. Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
  351. break;
  352. }
  353. IoMarkIrpPending(Irp);
  354. IoStartPacket(DeviceObject, Irp, NULL, NULL);
  355. return STATUS_PENDING;
  356. }
  357. case IOCTL_CDROM_READ_TOC_EX: {
  358. PCDROM_READ_TOC_EX inputBuffer;
  359. if (CdRomIsPlayActive(DeviceObject)) {
  360. status = STATUS_DEVICE_BUSY;
  361. break;
  362. }
  363. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  364. sizeof(CDROM_READ_TOC_EX)) {
  365. status = STATUS_INFO_LENGTH_MISMATCH;
  366. break;
  367. }
  368. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  369. MINIMUM_CDROM_READ_TOC_EX_SIZE) {
  370. status = STATUS_BUFFER_TOO_SMALL;
  371. Irp->IoStatus.Information = MINIMUM_CDROM_READ_TOC_EX_SIZE;
  372. break;
  373. }
  374. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength >
  375. ((USHORT)-1)) {
  376. status = STATUS_INVALID_PARAMETER;
  377. break;
  378. }
  379. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength &
  380. fdoExtension->AdapterDescriptor->AlignmentMask) {
  381. status = STATUS_INVALID_PARAMETER;
  382. break;
  383. }
  384. inputBuffer = Irp->AssociatedIrp.SystemBuffer;
  385. if ((inputBuffer->Reserved1 != 0) ||
  386. (inputBuffer->Reserved2 != 0) ||
  387. (inputBuffer->Reserved3 != 0)) {
  388. status = STATUS_INVALID_PARAMETER;
  389. break;
  390. }
  391. //
  392. // NOTE: when adding new formats, ensure that first two bytes
  393. // specify the amount of additional data available.
  394. //
  395. if ((inputBuffer->Format == CDROM_READ_TOC_EX_FORMAT_TOC ) ||
  396. (inputBuffer->Format == CDROM_READ_TOC_EX_FORMAT_FULL_TOC) ||
  397. (inputBuffer->Format == CDROM_READ_TOC_EX_FORMAT_CDTEXT )) {
  398. // SessionTrack field is used
  399. } else
  400. if ((inputBuffer->Format == CDROM_READ_TOC_EX_FORMAT_SESSION) ||
  401. (inputBuffer->Format == CDROM_READ_TOC_EX_FORMAT_PMA) ||
  402. (inputBuffer->Format == CDROM_READ_TOC_EX_FORMAT_ATIP)) {
  403. // SessionTrack field is reserved
  404. if (inputBuffer->SessionTrack != 0) {
  405. status = STATUS_INVALID_PARAMETER;
  406. break;
  407. }
  408. } else {
  409. status = STATUS_INVALID_PARAMETER;
  410. break;
  411. }
  412. IoMarkIrpPending(Irp);
  413. IoStartPacket(DeviceObject, Irp, NULL, NULL);
  414. return STATUS_PENDING;
  415. }
  416. case IOCTL_CDROM_GET_LAST_SESSION: {
  417. //
  418. // If the cd is playing music then reject this request.
  419. //
  420. if (CdRomIsPlayActive(DeviceObject)) {
  421. status = STATUS_DEVICE_BUSY;
  422. break;
  423. }
  424. //
  425. // Make sure the caller is requesting enough data to make this worth
  426. // our while.
  427. //
  428. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  429. sizeof(CDROM_TOC_SESSION_DATA)) {
  430. //
  431. // they didn't request the entire TOC -- use _EX version
  432. // for partial transfers and such.
  433. //
  434. status = STATUS_BUFFER_TOO_SMALL;
  435. Irp->IoStatus.Information = sizeof(CDROM_TOC_SESSION_DATA);
  436. break;
  437. }
  438. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength &
  439. fdoExtension->AdapterDescriptor->AlignmentMask) {
  440. status = STATUS_INVALID_PARAMETER;
  441. break;
  442. }
  443. IoMarkIrpPending(Irp);
  444. IoStartPacket(DeviceObject, Irp, NULL, NULL);
  445. return STATUS_PENDING;
  446. }
  447. case IOCTL_CDROM_READ_TOC: {
  448. //
  449. // If the cd is playing music then reject this request.
  450. //
  451. if (CdRomIsPlayActive(DeviceObject)) {
  452. status = STATUS_DEVICE_BUSY;
  453. break;
  454. }
  455. //
  456. // Make sure the caller is requesting enough data to make this worth
  457. // our while.
  458. //
  459. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  460. sizeof(CDROM_TOC)) {
  461. //
  462. // they didn't request the entire TOC -- use _EX version
  463. // for partial transfers and such.
  464. //
  465. status = STATUS_BUFFER_TOO_SMALL;
  466. Irp->IoStatus.Information = sizeof(CDROM_TOC);
  467. break;
  468. }
  469. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength &
  470. fdoExtension->AdapterDescriptor->AlignmentMask) {
  471. status = STATUS_INVALID_PARAMETER;
  472. break;
  473. }
  474. IoMarkIrpPending(Irp);
  475. IoStartPacket(DeviceObject, Irp, NULL, NULL);
  476. return STATUS_PENDING;
  477. }
  478. case IOCTL_CDROM_PLAY_AUDIO_MSF: {
  479. //
  480. // Play Audio MSF
  481. //
  482. TraceLog((CdromDebugTrace,
  483. "CdRomDeviceControl: Play audio MSF\n"));
  484. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  485. sizeof(CDROM_PLAY_AUDIO_MSF)) {
  486. //
  487. // Indicate unsuccessful status.
  488. //
  489. status = STATUS_INFO_LENGTH_MISMATCH;
  490. break;
  491. }
  492. IoMarkIrpPending(Irp);
  493. IoStartPacket(DeviceObject, Irp, NULL, NULL);
  494. return STATUS_PENDING;
  495. }
  496. case IOCTL_CDROM_SEEK_AUDIO_MSF: {
  497. //
  498. // Seek Audio MSF
  499. //
  500. TraceLog((CdromDebugTrace,
  501. "CdRomDeviceControl: Seek audio MSF\n"));
  502. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  503. sizeof(CDROM_SEEK_AUDIO_MSF)) {
  504. //
  505. // Indicate unsuccessful status.
  506. //
  507. status = STATUS_INFO_LENGTH_MISMATCH;
  508. break;
  509. }
  510. IoMarkIrpPending(Irp);
  511. IoStartPacket(DeviceObject, Irp, NULL, NULL);
  512. return STATUS_PENDING;
  513. }
  514. case IOCTL_CDROM_PAUSE_AUDIO: {
  515. //
  516. // Pause audio
  517. //
  518. TraceLog((CdromDebugTrace,
  519. "CdRomDeviceControl: Pause audio\n"));
  520. IoMarkIrpPending(Irp);
  521. IoStartPacket(DeviceObject, Irp, NULL, NULL);
  522. return STATUS_PENDING;
  523. break;
  524. }
  525. case IOCTL_CDROM_RESUME_AUDIO: {
  526. //
  527. // Resume audio
  528. //
  529. TraceLog((CdromDebugTrace,
  530. "CdRomDeviceControl: Resume audio\n"));
  531. IoMarkIrpPending(Irp);
  532. IoStartPacket(DeviceObject, Irp, NULL, NULL);
  533. return STATUS_PENDING;
  534. }
  535. case IOCTL_CDROM_READ_Q_CHANNEL: {
  536. PCDROM_SUB_Q_DATA_FORMAT inputBuffer =
  537. Irp->AssociatedIrp.SystemBuffer;
  538. ULONG transferByteCount;
  539. if(irpStack->Parameters.DeviceIoControl.InputBufferLength <
  540. sizeof(CDROM_SUB_Q_DATA_FORMAT)) {
  541. status = STATUS_INFO_LENGTH_MISMATCH;
  542. break;
  543. }
  544. //
  545. // check for all valid types of request
  546. //
  547. if (inputBuffer->Format == IOCTL_CDROM_CURRENT_POSITION) {
  548. transferByteCount = sizeof(SUB_Q_CURRENT_POSITION);
  549. } else if (inputBuffer->Format == IOCTL_CDROM_MEDIA_CATALOG) {
  550. transferByteCount = sizeof(SUB_Q_MEDIA_CATALOG_NUMBER);
  551. } else if (inputBuffer->Format == IOCTL_CDROM_TRACK_ISRC) {
  552. transferByteCount = sizeof(SUB_Q_TRACK_ISRC);
  553. } else {
  554. status = STATUS_INVALID_PARAMETER;
  555. Irp->IoStatus.Information = 0;
  556. break;
  557. }
  558. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  559. transferByteCount) {
  560. Irp->IoStatus.Information = transferByteCount;
  561. status = STATUS_BUFFER_TOO_SMALL;
  562. break;
  563. }
  564. IoMarkIrpPending(Irp);
  565. IoStartPacket(DeviceObject, Irp, NULL, NULL);
  566. return STATUS_PENDING;
  567. }
  568. case IOCTL_CDROM_GET_VOLUME: {
  569. TraceLog((CdromDebugTrace,
  570. "CdRomDeviceControl: Get volume control\n"));
  571. //
  572. // Verify user buffer is large enough for data.
  573. //
  574. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  575. sizeof(VOLUME_CONTROL)) {
  576. //
  577. // Indicate unsuccessful status and no data transferred.
  578. //
  579. status = STATUS_BUFFER_TOO_SMALL;
  580. Irp->IoStatus.Information = sizeof(VOLUME_CONTROL);
  581. break;
  582. }
  583. IoMarkIrpPending(Irp);
  584. IoStartPacket(DeviceObject, Irp, NULL, NULL);
  585. return STATUS_PENDING;
  586. }
  587. case IOCTL_CDROM_SET_VOLUME: {
  588. TraceLog((CdromDebugTrace,
  589. "CdRomDeviceControl: Set volume control\n"));
  590. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  591. sizeof(VOLUME_CONTROL)) {
  592. //
  593. // Indicate unsuccessful status.
  594. //
  595. status = STATUS_INFO_LENGTH_MISMATCH;
  596. break;
  597. }
  598. IoMarkIrpPending(Irp);
  599. IoStartPacket(DeviceObject, Irp, NULL, NULL);
  600. return STATUS_PENDING;
  601. }
  602. case IOCTL_CDROM_STOP_AUDIO: {
  603. //
  604. // Stop play.
  605. //
  606. TraceLog((CdromDebugTrace,
  607. "CdRomDeviceControl: Stop audio\n"));
  608. IoMarkIrpPending(Irp);
  609. IoStartPacket(DeviceObject, Irp, NULL, NULL);
  610. return STATUS_PENDING;
  611. }
  612. case IOCTL_STORAGE_CHECK_VERIFY:
  613. case IOCTL_DISK_CHECK_VERIFY:
  614. case IOCTL_CDROM_CHECK_VERIFY: {
  615. TraceLog((CdromDebugTrace,
  616. "CdRomDeviceControl: [%p] Check Verify\n", Irp));
  617. if((irpStack->Parameters.DeviceIoControl.OutputBufferLength) &&
  618. (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG))) {
  619. TraceLog((CdromDebugWarning,
  620. "CdRomDeviceControl: Check Verify: media count "
  621. "buffer too small\n"));
  622. status = STATUS_BUFFER_TOO_SMALL;
  623. Irp->IoStatus.Information = sizeof(ULONG);
  624. break;
  625. }
  626. IoMarkIrpPending(Irp);
  627. IoStartPacket(DeviceObject, Irp, NULL, NULL);
  628. return STATUS_PENDING;
  629. }
  630. case IOCTL_DVD_READ_STRUCTURE: {
  631. TraceLog((CdromDebugTrace,
  632. "DvdDeviceControl: [%p] IOCTL_DVD_READ_STRUCTURE\n", Irp));
  633. if (cdData->DvdRpc0Device && cdData->DvdRpc0LicenseFailure) {
  634. TraceLog((CdromDebugWarning,
  635. "DvdDeviceControl: License Failure\n"));
  636. status = STATUS_COPY_PROTECTION_FAILURE;
  637. break;
  638. }
  639. if (cdData->DvdRpc0Device && cdData->Rpc0RetryRegistryCallback) {
  640. //
  641. // if currently in-progress, this will just return.
  642. // prevents looping by doing that interlockedExchange()
  643. //
  644. TraceLog((CdromDebugWarning,
  645. "DvdDeviceControl: PickRegion() from "
  646. "READ_STRUCTURE\n"));
  647. CdRomPickDvdRegion(DeviceObject);
  648. }
  649. if(irpStack->Parameters.DeviceIoControl.InputBufferLength <
  650. sizeof(DVD_READ_STRUCTURE)) {
  651. TraceLog((CdromDebugWarning,
  652. "DvdDeviceControl - READ_STRUCTURE: input buffer "
  653. "length too small (was %d should be %d)\n",
  654. irpStack->Parameters.DeviceIoControl.InputBufferLength,
  655. sizeof(DVD_READ_STRUCTURE)));
  656. status = STATUS_INVALID_PARAMETER;
  657. break;
  658. }
  659. if(irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  660. sizeof(READ_DVD_STRUCTURES_HEADER)) {
  661. TraceLog((CdromDebugWarning,
  662. "DvdDeviceControl - READ_STRUCTURE: output buffer "
  663. "cannot hold header information\n"));
  664. status = STATUS_BUFFER_TOO_SMALL;
  665. Irp->IoStatus.Information = sizeof(READ_DVD_STRUCTURES_HEADER);
  666. break;
  667. }
  668. if(irpStack->Parameters.DeviceIoControl.OutputBufferLength >
  669. MAXUSHORT) {
  670. //
  671. // key length must fit in two bytes
  672. //
  673. TraceLog((CdromDebugWarning,
  674. "DvdDeviceControl - READ_STRUCTURE: output buffer "
  675. "too large\n"));
  676. status = STATUS_INVALID_PARAMETER;
  677. break;
  678. }
  679. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength &
  680. fdoExtension->AdapterDescriptor->AlignmentMask) {
  681. status = STATUS_INVALID_PARAMETER;
  682. break;
  683. }
  684. IoMarkIrpPending(Irp);
  685. IoStartPacket(DeviceObject, Irp, NULL, NULL);
  686. return STATUS_PENDING;
  687. }
  688. case IOCTL_DVD_START_SESSION: {
  689. TraceLog((CdromDebugTrace,
  690. "DvdDeviceControl: [%p] IOCTL_DVD_START_SESSION\n", Irp));
  691. if (cdData->DvdRpc0Device && cdData->DvdRpc0LicenseFailure) {
  692. TraceLog((CdromDebugWarning,
  693. "DvdDeviceControl: License Failure\n"));
  694. status = STATUS_COPY_PROTECTION_FAILURE;
  695. break;
  696. }
  697. if(irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  698. sizeof(DVD_SESSION_ID)) {
  699. TraceLog((CdromDebugWarning,
  700. "DvdDeviceControl: DVD_START_SESSION - output "
  701. "buffer too small\n"));
  702. status = STATUS_BUFFER_TOO_SMALL;
  703. Irp->IoStatus.Information = sizeof(DVD_SESSION_ID);
  704. break;
  705. }
  706. IoMarkIrpPending(Irp);
  707. IoStartPacket(DeviceObject, Irp, NULL, NULL);
  708. return STATUS_PENDING;
  709. }
  710. case IOCTL_DVD_SEND_KEY:
  711. case IOCTL_DVD_SEND_KEY2: {
  712. PDVD_COPY_PROTECT_KEY key = Irp->AssociatedIrp.SystemBuffer;
  713. ULONG keyLength;
  714. TraceLog((CdromDebugTrace,
  715. "DvdDeviceControl: [%p] IOCTL_DVD_SEND_KEY\n", Irp));
  716. if (cdData->DvdRpc0Device && cdData->DvdRpc0LicenseFailure) {
  717. TraceLog((CdromDebugWarning,
  718. "DvdDeviceControl: License Failure\n"));
  719. status = STATUS_COPY_PROTECTION_FAILURE;
  720. break;
  721. }
  722. if((irpStack->Parameters.DeviceIoControl.InputBufferLength <
  723. sizeof(DVD_COPY_PROTECT_KEY)) ||
  724. (irpStack->Parameters.DeviceIoControl.InputBufferLength !=
  725. key->KeyLength)) {
  726. //
  727. // Key is too small to have a header or the key length doesn't
  728. // match the input buffer length. Key must be invalid
  729. //
  730. TraceLog((CdromDebugWarning,
  731. "DvdDeviceControl: [%p] IOCTL_DVD_SEND_KEY - "
  732. "key is too small or does not match KeyLength\n",
  733. Irp));
  734. status = STATUS_INVALID_PARAMETER;
  735. break;
  736. }
  737. //
  738. // allow only certain key type (non-destructive) to go through
  739. // IOCTL_DVD_SEND_KEY (which only requires READ access to the device)
  740. //
  741. if (ioctlCode == IOCTL_DVD_SEND_KEY) {
  742. if ((key->KeyType != DvdChallengeKey) &&
  743. (key->KeyType != DvdBusKey2) &&
  744. (key->KeyType != DvdInvalidateAGID)) {
  745. status = STATUS_INVALID_PARAMETER;
  746. break;
  747. }
  748. } else {
  749. if ((key->KeyType != DvdChallengeKey) &&
  750. (key->KeyType != DvdBusKey1) &&
  751. (key->KeyType != DvdBusKey2) &&
  752. (key->KeyType != DvdTitleKey) &&
  753. (key->KeyType != DvdAsf) &&
  754. (key->KeyType != DvdSetRpcKey) &&
  755. (key->KeyType != DvdGetRpcKey) &&
  756. (key->KeyType != DvdDiskKey) &&
  757. (key->KeyType != DvdInvalidateAGID)) {
  758. status = STATUS_INVALID_PARAMETER;
  759. break;
  760. }
  761. }
  762. if (cdData->DvdRpc0Device) {
  763. if (key->KeyType == DvdSetRpcKey) {
  764. PDVD_SET_RPC_KEY rpcKey = (PDVD_SET_RPC_KEY) key->KeyData;
  765. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  766. DVD_SET_RPC_KEY_LENGTH) {
  767. status = STATUS_INVALID_PARAMETER;
  768. break;
  769. }
  770. //
  771. // we have a request to set region code
  772. // on a RPC0 device which doesn't support
  773. // region coding.
  774. //
  775. // we have to fake it.
  776. //
  777. KeWaitForMutexObject(
  778. &cdData->Rpc0RegionMutex,
  779. UserRequest,
  780. KernelMode,
  781. FALSE,
  782. NULL
  783. );
  784. if (cdData->DvdRpc0Device && cdData->Rpc0RetryRegistryCallback) {
  785. //
  786. // if currently in-progress, this will just return.
  787. // prevents looping by doing that interlockedExchange()
  788. //
  789. TraceLog((CdromDebugWarning,
  790. "DvdDeviceControl: PickRegion() from "
  791. "SEND_KEY\n"));
  792. CdRomPickDvdRegion(DeviceObject);
  793. }
  794. if (cdData->Rpc0SystemRegion == rpcKey->PreferredDriveRegionCode) {
  795. //
  796. // nothing to change
  797. //
  798. TraceLog((CdromDebugWarning,
  799. "DvdDeviceControl (%p) => not changing "
  800. "regions -- requesting current region\n",
  801. DeviceObject));
  802. status = STATUS_SUCCESS;
  803. } else if (cdData->Rpc0SystemRegionResetCount == 0) {
  804. //
  805. // not allowed to change it again
  806. //
  807. TraceLog((CdromDebugWarning,
  808. "DvdDeviceControl (%p) => no more region "
  809. "changes are allowed for this device\n",
  810. DeviceObject));
  811. status = STATUS_CSS_RESETS_EXHAUSTED;
  812. } else {
  813. ULONG i;
  814. UCHAR mask;
  815. ULONG bufferLen;
  816. PDVD_READ_STRUCTURE dvdReadStructure;
  817. PDVD_COPYRIGHT_DESCRIPTOR dvdCopyRight;
  818. IO_STATUS_BLOCK ioStatus = {0};
  819. UCHAR mediaRegionData;
  820. mask = ~rpcKey->PreferredDriveRegionCode;
  821. if (CountOfSetBitsUChar(mask) != 1) {
  822. status = STATUS_INVALID_DEVICE_REQUEST;
  823. break;
  824. }
  825. //
  826. // this test will always be TRUE except during initial
  827. // automatic selection of the first region.
  828. //
  829. if (cdData->Rpc0SystemRegion != 0xff) {
  830. //
  831. // make sure we have a media in the drive with the same
  832. // region code if the drive is already has a region set
  833. //
  834. TraceLog((CdromDebugTrace,
  835. "DvdDeviceControl (%p) => Checking "
  836. "media region\n",
  837. DeviceObject));
  838. bufferLen = max(sizeof(DVD_DESCRIPTOR_HEADER) +
  839. sizeof(DVD_COPYRIGHT_DESCRIPTOR),
  840. sizeof(DVD_READ_STRUCTURE)
  841. );
  842. dvdReadStructure = (PDVD_READ_STRUCTURE)
  843. ExAllocatePoolWithTag(PagedPool,
  844. bufferLen,
  845. DVD_TAG_RPC2_CHECK);
  846. if (dvdReadStructure == NULL) {
  847. status = STATUS_INSUFFICIENT_RESOURCES;
  848. KeReleaseMutex(&cdData->Rpc0RegionMutex,FALSE);
  849. break;
  850. }
  851. dvdCopyRight = (PDVD_COPYRIGHT_DESCRIPTOR)
  852. ((PDVD_DESCRIPTOR_HEADER) dvdReadStructure)->Data;
  853. //
  854. // check to see if we have a DVD device
  855. //
  856. RtlZeroMemory (dvdReadStructure, bufferLen);
  857. dvdReadStructure->Format = DvdCopyrightDescriptor;
  858. //
  859. // Build a request for READ_KEY
  860. //
  861. ClassSendDeviceIoControlSynchronous(
  862. IOCTL_DVD_READ_STRUCTURE,
  863. DeviceObject,
  864. dvdReadStructure,
  865. sizeof(DVD_READ_STRUCTURE),
  866. sizeof(DVD_DESCRIPTOR_HEADER) +
  867. sizeof(DVD_COPYRIGHT_DESCRIPTOR),
  868. FALSE,
  869. &ioStatus);
  870. //
  871. // this is just to prevent bugs from creeping in
  872. // if status is not set later in development
  873. //
  874. status = ioStatus.Status;
  875. //
  876. // handle errors
  877. //
  878. if (!NT_SUCCESS(status)) {
  879. KeReleaseMutex(&cdData->Rpc0RegionMutex,FALSE);
  880. ExFreePool(dvdReadStructure);
  881. status = STATUS_INVALID_DEVICE_REQUEST;
  882. break;
  883. }
  884. //
  885. // save the mediaRegionData before freeing the
  886. // allocated memory
  887. //
  888. mediaRegionData =
  889. dvdCopyRight->RegionManagementInformation;
  890. ExFreePool(dvdReadStructure);
  891. TraceLog((CdromDebugWarning,
  892. "DvdDeviceControl (%p) => new mask is %x"
  893. " MediaRegionData is %x\n", DeviceObject,
  894. rpcKey->PreferredDriveRegionCode,
  895. mediaRegionData));
  896. //
  897. // the media region must match the requested region
  898. // for RPC0 drives for initial region selection
  899. //
  900. if (((UCHAR)~(mediaRegionData | rpcKey->PreferredDriveRegionCode)) == 0) {
  901. KeReleaseMutex(&cdData->Rpc0RegionMutex,FALSE);
  902. status = STATUS_CSS_REGION_MISMATCH;
  903. break;
  904. }
  905. }
  906. //
  907. // now try to set the region
  908. //
  909. TraceLog((CdromDebugTrace,
  910. "DvdDeviceControl (%p) => Soft-Setting "
  911. "region of RPC1 device to %x\n",
  912. DeviceObject,
  913. rpcKey->PreferredDriveRegionCode
  914. ));
  915. status = CdRomSetRpc0Settings(DeviceObject,
  916. rpcKey->PreferredDriveRegionCode);
  917. if (!NT_SUCCESS(status)) {
  918. TraceLog((CdromDebugWarning,
  919. "DvdDeviceControl (%p) => Could not "
  920. "set region code (%x)\n",
  921. DeviceObject, status
  922. ));
  923. } else {
  924. TraceLog((CdromDebugTrace,
  925. "DvdDeviceControl (%p) => New region set "
  926. " for RPC1 drive\n", DeviceObject));
  927. //
  928. // if it worked, our extension is already updated.
  929. // release the mutex
  930. //
  931. DebugPrint ((4, "DvdDeviceControl (%p) => DVD current "
  932. "region bitmap 0x%x\n", DeviceObject,
  933. cdData->Rpc0SystemRegion));
  934. DebugPrint ((4, "DvdDeviceControl (%p) => DVD region "
  935. " reset Count 0x%x\n", DeviceObject,
  936. cdData->Rpc0SystemRegionResetCount));
  937. }
  938. }
  939. KeReleaseMutex(&cdData->Rpc0RegionMutex,FALSE);
  940. break;
  941. } // end of key->KeyType == DvdSetRpcKey
  942. } // end of Rpc0Device hacks
  943. IoMarkIrpPending(Irp);
  944. IoStartPacket(DeviceObject, Irp, NULL, NULL);
  945. return STATUS_PENDING;
  946. break;
  947. }
  948. case IOCTL_DVD_READ_KEY: {
  949. PDVD_COPY_PROTECT_KEY keyParameters = Irp->AssociatedIrp.SystemBuffer;
  950. ULONG keyLength;
  951. TraceLog((CdromDebugTrace,
  952. "DvdDeviceControl: [%p] IOCTL_DVD_READ_KEY\n", Irp));
  953. if (cdData->DvdRpc0Device && cdData->DvdRpc0LicenseFailure) {
  954. TraceLog((CdromDebugWarning,
  955. "DvdDeviceControl: License Failure\n"));
  956. status = STATUS_COPY_PROTECTION_FAILURE;
  957. break;
  958. }
  959. if (cdData->DvdRpc0Device && cdData->Rpc0RetryRegistryCallback) {
  960. TraceLog((CdromDebugWarning,
  961. "DvdDeviceControl: PickRegion() from READ_KEY\n"));
  962. CdRomPickDvdRegion(DeviceObject);
  963. }
  964. if(irpStack->Parameters.DeviceIoControl.InputBufferLength <
  965. sizeof(DVD_COPY_PROTECT_KEY)) {
  966. TraceLog((CdromDebugWarning,
  967. "DvdDeviceControl: EstablishDriveKey - challenge "
  968. "key buffer too small\n"));
  969. status = STATUS_INVALID_PARAMETER;
  970. break;
  971. }
  972. switch(keyParameters->KeyType) {
  973. case DvdChallengeKey: {
  974. C_ASSERT(sizeof(DVD_COPY_PROTECT_KEY) <= DVD_CHALLENGE_KEY_LENGTH);
  975. keyLength = DVD_CHALLENGE_KEY_LENGTH;
  976. break;
  977. }
  978. case DvdBusKey1:
  979. case DvdBusKey2: {
  980. C_ASSERT(sizeof(DVD_COPY_PROTECT_KEY) <= DVD_BUS_KEY_LENGTH);
  981. keyLength = DVD_BUS_KEY_LENGTH;
  982. break;
  983. }
  984. case DvdTitleKey: {
  985. C_ASSERT(sizeof(DVD_COPY_PROTECT_KEY) <= DVD_TITLE_KEY_LENGTH);
  986. keyLength = DVD_TITLE_KEY_LENGTH;
  987. break;
  988. }
  989. case DvdAsf: {
  990. C_ASSERT(sizeof(DVD_COPY_PROTECT_KEY) <= DVD_ASF_LENGTH);
  991. keyLength = DVD_ASF_LENGTH;
  992. break;
  993. }
  994. case DvdDiskKey: {
  995. C_ASSERT(sizeof(DVD_COPY_PROTECT_KEY) <= DVD_DISK_KEY_LENGTH);
  996. keyLength = DVD_DISK_KEY_LENGTH;
  997. break;
  998. }
  999. case DvdGetRpcKey: {
  1000. C_ASSERT(sizeof(DVD_COPY_PROTECT_KEY) <= DVD_RPC_KEY_LENGTH);
  1001. keyLength = DVD_RPC_KEY_LENGTH;
  1002. break;
  1003. }
  1004. default: {
  1005. keyLength = sizeof(DVD_COPY_PROTECT_KEY);
  1006. break;
  1007. }
  1008. }
  1009. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  1010. keyLength) {
  1011. TraceLog((CdromDebugWarning,
  1012. "DvdDeviceControl: EstablishDriveKey - output "
  1013. "buffer too small\n"));
  1014. status = STATUS_BUFFER_TOO_SMALL;
  1015. Irp->IoStatus.Information = keyLength;
  1016. break;
  1017. }
  1018. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength &
  1019. fdoExtension->AdapterDescriptor->AlignmentMask) {
  1020. status = STATUS_INVALID_PARAMETER;
  1021. break;
  1022. }
  1023. if (keyParameters->KeyType == DvdGetRpcKey) {
  1024. CdRomPickDvdRegion(DeviceObject);
  1025. }
  1026. if ((keyParameters->KeyType == DvdGetRpcKey) &&
  1027. (cdData->DvdRpc0Device)) {
  1028. PDVD_RPC_KEY rpcKey;
  1029. rpcKey = (PDVD_RPC_KEY)keyParameters->KeyData;
  1030. RtlZeroMemory (rpcKey, sizeof (*rpcKey));
  1031. KeWaitForMutexObject(
  1032. &cdData->Rpc0RegionMutex,
  1033. UserRequest,
  1034. KernelMode,
  1035. FALSE,
  1036. NULL
  1037. );
  1038. //
  1039. // make up the data
  1040. //
  1041. rpcKey->UserResetsAvailable = cdData->Rpc0SystemRegionResetCount;
  1042. rpcKey->ManufacturerResetsAvailable = 0;
  1043. if (cdData->Rpc0SystemRegion == 0xff) {
  1044. rpcKey->TypeCode = 0;
  1045. } else {
  1046. rpcKey->TypeCode = 1;
  1047. }
  1048. rpcKey->RegionMask = (UCHAR) cdData->Rpc0SystemRegion;
  1049. rpcKey->RpcScheme = 1;
  1050. KeReleaseMutex(
  1051. &cdData->Rpc0RegionMutex,
  1052. FALSE
  1053. );
  1054. Irp->IoStatus.Information = DVD_RPC_KEY_LENGTH;
  1055. status = STATUS_SUCCESS;
  1056. break;
  1057. } else if (keyParameters->KeyType == DvdDiskKey) {
  1058. PDVD_COPY_PROTECT_KEY keyHeader;
  1059. PDVD_READ_STRUCTURE readStructureRequest;
  1060. //
  1061. // Special case - build a request to get the dvd structure
  1062. // so we can get the disk key.
  1063. //
  1064. //
  1065. // save the key header so we can restore the interesting
  1066. // parts later
  1067. //
  1068. keyHeader = ExAllocatePoolWithTag(NonPagedPool,
  1069. sizeof(DVD_COPY_PROTECT_KEY),
  1070. DVD_TAG_READ_KEY);
  1071. if(keyHeader == NULL) {
  1072. //
  1073. // Can't save the context so return an error
  1074. //
  1075. TraceLog((CdromDebugWarning,
  1076. "DvdDeviceControl - READ_KEY: unable to "
  1077. "allocate context\n"));
  1078. status = STATUS_INSUFFICIENT_RESOURCES;
  1079. break;
  1080. }
  1081. RtlCopyMemory(keyHeader,
  1082. Irp->AssociatedIrp.SystemBuffer,
  1083. sizeof(DVD_COPY_PROTECT_KEY));
  1084. IoCopyCurrentIrpStackLocationToNext(Irp);
  1085. nextStack = IoGetNextIrpStackLocation(Irp);
  1086. nextStack->Parameters.DeviceIoControl.IoControlCode =
  1087. IOCTL_DVD_READ_STRUCTURE;
  1088. readStructureRequest = Irp->AssociatedIrp.SystemBuffer;
  1089. readStructureRequest->Format = DvdDiskKeyDescriptor;
  1090. readStructureRequest->BlockByteOffset.QuadPart = 0;
  1091. readStructureRequest->LayerNumber = 0;
  1092. readStructureRequest->SessionId = keyHeader->SessionId;
  1093. nextStack->Parameters.DeviceIoControl.InputBufferLength =
  1094. sizeof(DVD_READ_STRUCTURE);
  1095. nextStack->Parameters.DeviceIoControl.OutputBufferLength =
  1096. sizeof(READ_DVD_STRUCTURES_HEADER) + sizeof(DVD_DISK_KEY_DESCRIPTOR);
  1097. IoSetCompletionRoutine(Irp,
  1098. CdRomDvdReadDiskKeyCompletion,
  1099. (PVOID) keyHeader,
  1100. TRUE,
  1101. TRUE,
  1102. TRUE);
  1103. {
  1104. UCHAR uniqueAddress;
  1105. ClassAcquireRemoveLock(DeviceObject, (PIRP)&uniqueAddress);
  1106. ClassReleaseRemoveLock(DeviceObject, Irp);
  1107. IoMarkIrpPending(Irp);
  1108. IoCallDriver(commonExtension->DeviceObject, Irp);
  1109. status = STATUS_PENDING;
  1110. ClassReleaseRemoveLock(DeviceObject, (PIRP)&uniqueAddress);
  1111. }
  1112. return STATUS_PENDING;
  1113. } else {
  1114. IoMarkIrpPending(Irp);
  1115. IoStartPacket(DeviceObject, Irp, NULL, NULL);
  1116. }
  1117. return STATUS_PENDING;
  1118. }
  1119. case IOCTL_DVD_END_SESSION: {
  1120. PDVD_SESSION_ID sessionId = Irp->AssociatedIrp.SystemBuffer;
  1121. TraceLog((CdromDebugTrace,
  1122. "DvdDeviceControl: [%p] END_SESSION\n", Irp));
  1123. if (cdData->DvdRpc0Device && cdData->DvdRpc0LicenseFailure) {
  1124. TraceLog((CdromDebugWarning,
  1125. "DvdDeviceControl: License Failure\n"));
  1126. status = STATUS_COPY_PROTECTION_FAILURE;
  1127. break;
  1128. }
  1129. if(irpStack->Parameters.DeviceIoControl.InputBufferLength <
  1130. sizeof(DVD_SESSION_ID)) {
  1131. TraceLog((CdromDebugWarning,
  1132. "DvdDeviceControl: EndSession - input buffer too "
  1133. "small\n"));
  1134. status = STATUS_INVALID_PARAMETER;
  1135. break;
  1136. }
  1137. IoMarkIrpPending(Irp);
  1138. if(*sessionId == DVD_END_ALL_SESSIONS) {
  1139. status = CdRomDvdEndAllSessionsCompletion(DeviceObject, Irp, NULL);
  1140. if(status == STATUS_SUCCESS) {
  1141. //
  1142. // Just complete the request - it was never issued to the
  1143. // lower device
  1144. //
  1145. break;
  1146. } else {
  1147. return STATUS_PENDING;
  1148. }
  1149. }
  1150. IoStartPacket(DeviceObject, Irp, NULL, NULL);
  1151. return STATUS_PENDING;
  1152. }
  1153. case IOCTL_DVD_GET_REGION: {
  1154. PDVD_COPY_PROTECT_KEY copyProtectKey;
  1155. ULONG keyLength;
  1156. IO_STATUS_BLOCK ioStatus = {0};
  1157. PDVD_DESCRIPTOR_HEADER dvdHeader;
  1158. PDVD_COPYRIGHT_DESCRIPTOR copyRightDescriptor;
  1159. PDVD_REGION dvdRegion;
  1160. PDVD_READ_STRUCTURE readStructure;
  1161. PDVD_RPC_KEY rpcKey;
  1162. TraceLog((CdromDebugTrace,
  1163. "DvdDeviceControl: [%p] IOCTL_DVD_GET_REGION\n", Irp));
  1164. if (cdData->DvdRpc0Device && cdData->DvdRpc0LicenseFailure) {
  1165. TraceLog((CdromDebugWarning,
  1166. "DvdDeviceControl: License Failure\n"));
  1167. status = STATUS_COPY_PROTECTION_FAILURE;
  1168. break;
  1169. }
  1170. if(irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  1171. sizeof(DVD_REGION)) {
  1172. TraceLog((CdromDebugWarning,
  1173. "DvdDeviceControl: output buffer DVD_REGION too small\n"));
  1174. status = STATUS_INVALID_PARAMETER;
  1175. break;
  1176. }
  1177. //
  1178. // figure out how much data buffer we need
  1179. //
  1180. keyLength = max(sizeof(DVD_DESCRIPTOR_HEADER) +
  1181. sizeof(DVD_COPYRIGHT_DESCRIPTOR),
  1182. sizeof(DVD_READ_STRUCTURE)
  1183. );
  1184. keyLength = max(keyLength,
  1185. DVD_RPC_KEY_LENGTH
  1186. );
  1187. //
  1188. // round the size to nearest ULONGLONG -- why?
  1189. // could this be to deal with device alignment issues?
  1190. //
  1191. keyLength += sizeof(ULONGLONG) - (keyLength & (sizeof(ULONGLONG) - 1));
  1192. readStructure = ExAllocatePoolWithTag(NonPagedPool,
  1193. keyLength,
  1194. DVD_TAG_READ_KEY);
  1195. if (readStructure == NULL) {
  1196. status = STATUS_INSUFFICIENT_RESOURCES;
  1197. break;
  1198. }
  1199. RtlZeroMemory (readStructure, keyLength);
  1200. readStructure->Format = DvdCopyrightDescriptor;
  1201. //
  1202. // Build a request for READ_STRUCTURE
  1203. //
  1204. ClassSendDeviceIoControlSynchronous(
  1205. IOCTL_DVD_READ_STRUCTURE,
  1206. DeviceObject,
  1207. readStructure,
  1208. keyLength,
  1209. sizeof(DVD_DESCRIPTOR_HEADER) +
  1210. sizeof(DVD_COPYRIGHT_DESCRIPTOR),
  1211. FALSE,
  1212. &ioStatus);
  1213. status = ioStatus.Status;
  1214. if (!NT_SUCCESS(status)) {
  1215. TraceLog((CdromDebugWarning,
  1216. "CdRomDvdGetRegion => read structure failed %x\n",
  1217. status));
  1218. ExFreePool(readStructure);
  1219. break;
  1220. }
  1221. //
  1222. // we got the copyright descriptor, so now get the region if possible
  1223. //
  1224. dvdHeader = (PDVD_DESCRIPTOR_HEADER) readStructure;
  1225. copyRightDescriptor = (PDVD_COPYRIGHT_DESCRIPTOR) dvdHeader->Data;
  1226. //
  1227. // the original irp's systembuffer has a copy of the info that
  1228. // should be passed down in the request
  1229. //
  1230. dvdRegion = Irp->AssociatedIrp.SystemBuffer;
  1231. dvdRegion->CopySystem = copyRightDescriptor->CopyrightProtectionType;
  1232. dvdRegion->RegionData = copyRightDescriptor->RegionManagementInformation;
  1233. //
  1234. // now reuse the buffer to request the copy protection info
  1235. //
  1236. copyProtectKey = (PDVD_COPY_PROTECT_KEY) readStructure;
  1237. RtlZeroMemory (copyProtectKey, DVD_RPC_KEY_LENGTH);
  1238. copyProtectKey->KeyLength = DVD_RPC_KEY_LENGTH;
  1239. copyProtectKey->KeyType = DvdGetRpcKey;
  1240. //
  1241. // send a request for READ_KEY
  1242. //
  1243. ClassSendDeviceIoControlSynchronous(
  1244. IOCTL_DVD_READ_KEY,
  1245. DeviceObject,
  1246. copyProtectKey,
  1247. DVD_RPC_KEY_LENGTH,
  1248. DVD_RPC_KEY_LENGTH,
  1249. FALSE,
  1250. &ioStatus);
  1251. status = ioStatus.Status;
  1252. if (!NT_SUCCESS(status)) {
  1253. TraceLog((CdromDebugWarning,
  1254. "CdRomDvdGetRegion => read key failed %x\n",
  1255. status));
  1256. ExFreePool(readStructure);
  1257. break;
  1258. }
  1259. //
  1260. // the request succeeded. if a supported scheme is returned,
  1261. // then return the information to the caller
  1262. //
  1263. rpcKey = (PDVD_RPC_KEY) copyProtectKey->KeyData;
  1264. if (rpcKey->RpcScheme == 1) {
  1265. if (rpcKey->TypeCode) {
  1266. dvdRegion->SystemRegion = ~rpcKey->RegionMask;
  1267. dvdRegion->ResetCount = rpcKey->UserResetsAvailable;
  1268. } else {
  1269. //
  1270. // the drive has not been set for any region
  1271. //
  1272. dvdRegion->SystemRegion = 0;
  1273. dvdRegion->ResetCount = rpcKey->UserResetsAvailable;
  1274. }
  1275. Irp->IoStatus.Information = sizeof(DVD_REGION);
  1276. } else {
  1277. TraceLog((CdromDebugWarning,
  1278. "CdRomDvdGetRegion => rpcKey->RpcScheme != 1\n"));
  1279. status = STATUS_INVALID_DEVICE_REQUEST;
  1280. }
  1281. ExFreePool(readStructure);
  1282. break;
  1283. }
  1284. case IOCTL_STORAGE_SET_READ_AHEAD: {
  1285. if(irpStack->Parameters.DeviceIoControl.InputBufferLength <
  1286. sizeof(STORAGE_SET_READ_AHEAD)) {
  1287. TraceLog((CdromDebugWarning,
  1288. "DvdDeviceControl: SetReadAhead buffer too small\n"));
  1289. status = STATUS_INVALID_PARAMETER;
  1290. break;
  1291. }
  1292. IoMarkIrpPending(Irp);
  1293. IoStartPacket(DeviceObject, Irp, NULL, NULL);
  1294. return STATUS_PENDING;
  1295. }
  1296. case IOCTL_DISK_IS_WRITABLE: {
  1297. // all verification done in StartIo()
  1298. IoMarkIrpPending(Irp);
  1299. IoStartPacket(DeviceObject, Irp, NULL, NULL);
  1300. return STATUS_PENDING;
  1301. }
  1302. case IOCTL_DISK_GET_DRIVE_LAYOUT: {
  1303. ULONG size;
  1304. //
  1305. // we always fake zero or one partitions, and one partition
  1306. // structure is included in DRIVE_LAYOUT_INFORMATION
  1307. //
  1308. size = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION, PartitionEntry[1]);
  1309. TraceLog((CdromDebugTrace,
  1310. "CdRomDeviceControl: Get drive layout\n"));
  1311. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < size) {
  1312. status = STATUS_BUFFER_TOO_SMALL;
  1313. Irp->IoStatus.Information = size;
  1314. break;
  1315. }
  1316. IoMarkIrpPending(Irp);
  1317. IoStartPacket(DeviceObject, Irp, NULL, NULL);
  1318. return STATUS_PENDING;
  1319. }
  1320. case IOCTL_DISK_GET_DRIVE_LAYOUT_EX: {
  1321. ULONG size;
  1322. //
  1323. // we always fake zero or one partitions, and one partition
  1324. // structure is included in DRIVE_LAYOUT_INFORMATION_EX
  1325. //
  1326. size = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[1]);
  1327. TraceLog((CdromDebugTrace,
  1328. "CdRomDeviceControl: Get drive layout ex\n"));
  1329. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < size) {
  1330. status = STATUS_BUFFER_TOO_SMALL;
  1331. Irp->IoStatus.Information = size;
  1332. break;
  1333. }
  1334. IoMarkIrpPending(Irp);
  1335. IoStartPacket(DeviceObject, Irp, NULL, NULL);
  1336. return STATUS_PENDING;
  1337. }
  1338. case IOCTL_DISK_GET_PARTITION_INFO: {
  1339. //
  1340. // Check that the buffer is large enough.
  1341. //
  1342. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  1343. sizeof(PARTITION_INFORMATION)) {
  1344. status = STATUS_BUFFER_TOO_SMALL;
  1345. Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);
  1346. break;
  1347. }
  1348. IoMarkIrpPending(Irp);
  1349. IoStartPacket(DeviceObject, Irp, NULL, NULL);
  1350. return STATUS_PENDING;
  1351. }
  1352. case IOCTL_DISK_GET_PARTITION_INFO_EX: {
  1353. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  1354. sizeof(PARTITION_INFORMATION_EX)) {
  1355. status = STATUS_BUFFER_TOO_SMALL;
  1356. Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION_EX);
  1357. break;
  1358. }
  1359. IoMarkIrpPending(Irp);
  1360. IoStartPacket(DeviceObject, Irp, NULL, NULL);
  1361. return STATUS_PENDING;
  1362. }
  1363. case IOCTL_DISK_VERIFY: {
  1364. TraceLog((CdromDebugTrace,
  1365. "IOCTL_DISK_VERIFY to device %p through irp %p\n",
  1366. DeviceObject, Irp));
  1367. //
  1368. // Validate buffer length.
  1369. //
  1370. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  1371. sizeof(VERIFY_INFORMATION)) {
  1372. status = STATUS_INFO_LENGTH_MISMATCH;
  1373. break;
  1374. }
  1375. IoMarkIrpPending(Irp);
  1376. IoStartPacket(DeviceObject, Irp, NULL, NULL);
  1377. return STATUS_PENDING;
  1378. }
  1379. case IOCTL_DISK_GET_LENGTH_INFO: {
  1380. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  1381. sizeof(GET_LENGTH_INFORMATION)) {
  1382. status = STATUS_BUFFER_TOO_SMALL;
  1383. Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION);
  1384. break;
  1385. }
  1386. IoMarkIrpPending(Irp);
  1387. IoStartPacket(DeviceObject, Irp, NULL, NULL);
  1388. return STATUS_PENDING;
  1389. }
  1390. case IOCTL_CDROM_GET_CONFIGURATION: {
  1391. PGET_CONFIGURATION_IOCTL_INPUT inputBuffer;
  1392. TraceLog((CdromDebugTrace,
  1393. "IOCTL_CDROM_GET_CONFIGURATION to via irp %p\n", Irp));
  1394. //
  1395. // Validate buffer length.
  1396. //
  1397. if (irpStack->Parameters.DeviceIoControl.InputBufferLength !=
  1398. sizeof(GET_CONFIGURATION_IOCTL_INPUT)) {
  1399. status = STATUS_INFO_LENGTH_MISMATCH;
  1400. break;
  1401. }
  1402. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  1403. sizeof(GET_CONFIGURATION_HEADER)) {
  1404. status = STATUS_BUFFER_TOO_SMALL;
  1405. Irp->IoStatus.Information = sizeof(GET_CONFIGURATION_HEADER);
  1406. break;
  1407. }
  1408. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength > 0xffff) {
  1409. // output buffer is too large
  1410. status = STATUS_INVALID_BUFFER_SIZE;
  1411. break;
  1412. }
  1413. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength &
  1414. fdoExtension->AdapterDescriptor->AlignmentMask) {
  1415. // buffer is not proper size multiple
  1416. status = STATUS_INVALID_PARAMETER;
  1417. break;
  1418. }
  1419. //
  1420. // also verify the arguments are reasonable.
  1421. //
  1422. inputBuffer = Irp->AssociatedIrp.SystemBuffer;
  1423. if (inputBuffer->Feature > 0xffff) {
  1424. status = STATUS_INVALID_PARAMETER;
  1425. break;
  1426. }
  1427. if ((inputBuffer->RequestType != SCSI_GET_CONFIGURATION_REQUEST_TYPE_ONE) &&
  1428. (inputBuffer->RequestType != SCSI_GET_CONFIGURATION_REQUEST_TYPE_CURRENT) &&
  1429. (inputBuffer->RequestType != SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL)) {
  1430. status = STATUS_INVALID_PARAMETER;
  1431. break;
  1432. }
  1433. if (inputBuffer->Reserved[0] || inputBuffer->Reserved[1]) {
  1434. status = STATUS_INVALID_PARAMETER;
  1435. break;
  1436. }
  1437. IoMarkIrpPending(Irp);
  1438. IoStartPacket(DeviceObject, Irp, NULL, NULL);
  1439. return STATUS_PENDING;
  1440. }
  1441. default: {
  1442. BOOLEAN synchronize = (KeGetCurrentIrql() == PASSIVE_LEVEL);
  1443. PKEVENT deviceControlEvent;
  1444. //
  1445. // If the ioctl has come in at passive level then we will synchronize
  1446. // with our start-io routine when sending the ioctl. If the ioctl
  1447. // has come in at a higher interrupt level and it was not handled
  1448. // above then it's unlikely to be a request for the class DLL - however
  1449. // we'll still use it's common code to forward the request through.
  1450. //
  1451. if (synchronize) {
  1452. deviceControlEvent = ExAllocatePoolWithTag(NonPagedPool,
  1453. sizeof(KEVENT),
  1454. CDROM_TAG_DC_EVENT);
  1455. if (deviceControlEvent == NULL) {
  1456. //
  1457. // must complete this irp unsuccessful here
  1458. //
  1459. status = STATUS_INSUFFICIENT_RESOURCES;
  1460. break;
  1461. } else {
  1462. PIO_STACK_LOCATION currentStack;
  1463. UCHAR uniqueAddress;
  1464. KeInitializeEvent(deviceControlEvent, NotificationEvent, FALSE);
  1465. currentStack = IoGetCurrentIrpStackLocation(Irp);
  1466. nextStack = IoGetNextIrpStackLocation(Irp);
  1467. //
  1468. // Copy the stack down a notch
  1469. //
  1470. IoCopyCurrentIrpStackLocationToNext(Irp);
  1471. IoSetCompletionRoutine(
  1472. Irp,
  1473. CdRomClassIoctlCompletion,
  1474. deviceControlEvent,
  1475. TRUE,
  1476. TRUE,
  1477. TRUE
  1478. );
  1479. IoSetNextIrpStackLocation(Irp);
  1480. Irp->IoStatus.Status = STATUS_SUCCESS;
  1481. Irp->IoStatus.Information = 0;
  1482. //
  1483. // Override volume verifies on this stack location so that we
  1484. // will be forced through the synchronization. Once this
  1485. // location goes away we get the old value back
  1486. //
  1487. SET_FLAG(nextStack->Flags, SL_OVERRIDE_VERIFY_VOLUME);
  1488. //
  1489. // because this will release the remove lock (even though it
  1490. // reacquires it in the completion routine) it is neccessary
  1491. // to acquire another remove lock here.
  1492. //
  1493. ClassAcquireRemoveLock(DeviceObject, (PIRP) &uniqueAddress);
  1494. //
  1495. // send the request into CDROM's StartIo (which will
  1496. // complete the request and release the remove lock).
  1497. // note: the completion routine will re-acquire the
  1498. // remove lock.
  1499. //
  1500. IoStartPacket(DeviceObject, Irp, NULL, NULL);
  1501. //
  1502. // Wait for CdRomClassIoctlCompletion to set the event. This
  1503. // ensures serialization remains intact for these unhandled device
  1504. // controls.
  1505. //
  1506. KeWaitForSingleObject(
  1507. deviceControlEvent,
  1508. Executive,
  1509. KernelMode,
  1510. FALSE,
  1511. NULL);
  1512. //
  1513. // release the remove lock and free the pool for the event
  1514. //
  1515. ClassReleaseRemoveLock(DeviceObject, (PIRP) &uniqueAddress);
  1516. ExFreePool(deviceControlEvent);
  1517. TraceLog((CdromDebugTrace,
  1518. "CdRomDeviceControl: irp %p synchronized\n", Irp));
  1519. status = Irp->IoStatus.Status;
  1520. }
  1521. } else {
  1522. status = STATUS_SUCCESS;
  1523. }
  1524. //
  1525. // If an error occured then propagate that back up - we are no longer
  1526. // guaranteed synchronization and the upper layers will have to
  1527. // retry.
  1528. //
  1529. // If no error occured, call down to the class driver directly
  1530. // then start up the next request.
  1531. //
  1532. if (NT_SUCCESS(status)) {
  1533. UCHAR uniqueAddress;
  1534. //
  1535. // The class device control routine will release the remove
  1536. // lock for this Irp. We need to make sure we have one
  1537. // available so that it's safe to call IoStartNextPacket
  1538. //
  1539. if(synchronize) {
  1540. ClassAcquireRemoveLock(DeviceObject, (PIRP)&uniqueAddress);
  1541. }
  1542. status = ClassDeviceControl(DeviceObject, Irp);
  1543. if(synchronize) {
  1544. KeRaiseIrql(DISPATCH_LEVEL, &irql);
  1545. IoStartNextPacket(DeviceObject, FALSE);
  1546. KeLowerIrql(irql);
  1547. ClassReleaseRemoveLock(DeviceObject, (PIRP)&uniqueAddress);
  1548. }
  1549. return status;
  1550. }
  1551. //
  1552. // an error occurred (either STATUS_INSUFFICIENT_RESOURCES from
  1553. // attempting to synchronize or StartIo() error'd this one
  1554. // out), so we need to finish the irp, which is
  1555. // done at the end of this routine.
  1556. //
  1557. break;
  1558. } // end default case
  1559. } // end switch()
  1560. if (status == STATUS_VERIFY_REQUIRED) {
  1561. //
  1562. // If the status is verified required and this request
  1563. // should bypass verify required then retry the request.
  1564. //
  1565. if (irpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME) {
  1566. status = STATUS_IO_DEVICE_ERROR;
  1567. goto RetryControl;
  1568. }
  1569. }
  1570. if (IoIsErrorUserInduced(status)) {
  1571. if (Irp->Tail.Overlay.Thread) {
  1572. IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
  1573. }
  1574. }
  1575. //
  1576. // Update IRP with completion status.
  1577. //
  1578. Irp->IoStatus.Status = status;
  1579. //
  1580. // Complete the request.
  1581. //
  1582. ClassReleaseRemoveLock(DeviceObject, Irp);
  1583. ClassCompleteRequest(DeviceObject, Irp, IO_DISK_INCREMENT);
  1584. TraceLog((CdromDebugTrace,
  1585. "CdRomDeviceControl: Status is %lx\n", status));
  1586. return status;
  1587. } // end CdRomDeviceControl()
  1588. NTSTATUS
  1589. CdRomClassIoctlCompletion(
  1590. IN PDEVICE_OBJECT DeviceObject,
  1591. IN PIRP Irp,
  1592. IN PVOID Context
  1593. )
  1594. /*++
  1595. Routine Description:
  1596. This routine signals the event used by CdRomDeviceControl to synchronize
  1597. class driver (and lower level driver) ioctls with cdrom's startio routine.
  1598. The irp completion is short-circuited so that CdRomDeviceControlDispatch
  1599. can reissue it once it wakes up.
  1600. Arguments:
  1601. DeviceObject - the device object
  1602. Irp - the request we are synchronizing
  1603. Context - a PKEVENT that we need to signal
  1604. Return Value:
  1605. NTSTATUS
  1606. --*/
  1607. {
  1608. PKEVENT syncEvent = (PKEVENT) Context;
  1609. TraceLog((CdromDebugTrace,
  1610. "CdRomClassIoctlCompletion: setting event for irp %p\n", Irp));
  1611. //
  1612. // We released the lock when we completed this request. Reacquire it.
  1613. //
  1614. ClassAcquireRemoveLock(DeviceObject, Irp);
  1615. KeSetEvent(syncEvent, IO_DISK_INCREMENT, FALSE);
  1616. return STATUS_MORE_PROCESSING_REQUIRED;
  1617. }
  1618. NTSTATUS
  1619. CdRomDeviceControlCompletion(
  1620. IN PDEVICE_OBJECT DeviceObject,
  1621. IN PIRP Irp,
  1622. IN PVOID Context
  1623. )
  1624. {
  1625. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  1626. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  1627. PCDROM_DATA cdData = (PCDROM_DATA)(commonExtension->DriverData);
  1628. BOOLEAN use6Byte = TEST_FLAG(cdData->XAFlags, XA_USE_6_BYTE);
  1629. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  1630. PIO_STACK_LOCATION realIrpStack;
  1631. PIO_STACK_LOCATION realIrpNextStack;
  1632. PSCSI_REQUEST_BLOCK srb = Context;
  1633. PIRP realIrp = NULL;
  1634. NTSTATUS status;
  1635. BOOLEAN retry;
  1636. //
  1637. // Extract the 'real' irp from the irpstack.
  1638. //
  1639. realIrp = (PIRP) irpStack->Parameters.Others.Argument2;
  1640. realIrpStack = IoGetCurrentIrpStackLocation(realIrp);
  1641. realIrpNextStack = IoGetNextIrpStackLocation(realIrp);
  1642. //
  1643. // check that we've really got the correct irp
  1644. //
  1645. ASSERT(realIrpNextStack->Parameters.Others.Argument3 == Irp);
  1646. //
  1647. // Check SRB status for success of completing request.
  1648. //
  1649. if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
  1650. ULONG retryInterval;
  1651. TraceLog((CdromDebugTrace,
  1652. "CdRomDeviceControlCompletion: Irp %p, Srb %p Real Irp %p Status %lx\n",
  1653. Irp,
  1654. srb,
  1655. realIrp,
  1656. srb->SrbStatus));
  1657. //
  1658. // Release the queue if it is frozen.
  1659. //
  1660. if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
  1661. TraceLog((CdromDebugTrace,
  1662. "CdRomDeviceControlCompletion: Releasing Queue\n"));
  1663. ClassReleaseQueue(DeviceObject);
  1664. }
  1665. retry = ClassInterpretSenseInfo(DeviceObject,
  1666. srb,
  1667. irpStack->MajorFunction,
  1668. irpStack->Parameters.DeviceIoControl.IoControlCode,
  1669. MAXIMUM_RETRIES - ((ULONG)(ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1),
  1670. &status,
  1671. &retryInterval);
  1672. TraceLog((CdromDebugTrace,
  1673. "CdRomDeviceControlCompletion: IRP will %sbe retried\n",
  1674. (retry ? "" : "not ")));
  1675. //
  1676. // Some of the Device Controls need special cases on non-Success status's.
  1677. //
  1678. if (realIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
  1679. if ((realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_GET_LAST_SESSION) ||
  1680. (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_READ_TOC) ||
  1681. (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_READ_TOC_EX) ||
  1682. (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_GET_VOLUME)) {
  1683. if (status == STATUS_DATA_OVERRUN) {
  1684. status = STATUS_SUCCESS;
  1685. retry = FALSE;
  1686. }
  1687. }
  1688. if (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_READ_Q_CHANNEL) {
  1689. PLAY_ACTIVE(fdoExtension) = FALSE;
  1690. }
  1691. }
  1692. //
  1693. // If the status is verified required and the this request
  1694. // should bypass verify required then retry the request.
  1695. //
  1696. if (realIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
  1697. status == STATUS_VERIFY_REQUIRED) {
  1698. // note: status gets overwritten here
  1699. status = STATUS_IO_DEVICE_ERROR;
  1700. retry = TRUE;
  1701. if (((realIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) ||
  1702. (realIrpStack->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL)
  1703. ) &&
  1704. ((realIrpStack->Parameters.DeviceIoControl.IoControlCode ==
  1705. IOCTL_CDROM_CHECK_VERIFY) ||
  1706. (realIrpStack->Parameters.DeviceIoControl.IoControlCode ==
  1707. IOCTL_STORAGE_CHECK_VERIFY) ||
  1708. (realIrpStack->Parameters.DeviceIoControl.IoControlCode ==
  1709. IOCTL_STORAGE_CHECK_VERIFY2) ||
  1710. (realIrpStack->Parameters.DeviceIoControl.IoControlCode ==
  1711. IOCTL_DISK_CHECK_VERIFY)
  1712. )
  1713. ) {
  1714. //
  1715. // Update the geometry information, as the media could have
  1716. // changed. The completion routine for this will complete
  1717. // the real irp and start the next packet.
  1718. //
  1719. if (srb) {
  1720. if (srb->SenseInfoBuffer) {
  1721. ExFreePool(srb->SenseInfoBuffer);
  1722. }
  1723. if (srb->DataBuffer) {
  1724. ExFreePool(srb->DataBuffer);
  1725. }
  1726. ExFreePool(srb);
  1727. srb = NULL;
  1728. }
  1729. if (Irp->MdlAddress) {
  1730. IoFreeMdl(Irp->MdlAddress);
  1731. Irp->MdlAddress = NULL;
  1732. }
  1733. IoFreeIrp(Irp);
  1734. Irp = NULL;
  1735. status = CdRomUpdateCapacity(fdoExtension, realIrp, NULL);
  1736. TraceLog((CdromDebugTrace,
  1737. "CdRomDeviceControlCompletion: [%p] "
  1738. "CdRomUpdateCapacity completed with status %lx\n",
  1739. realIrp, status));
  1740. //
  1741. // needed to update the capacity.
  1742. // the irp's already handed off to CdRomUpdateCapacity().
  1743. // we've already free'd the current irp.
  1744. // nothing left to do in this code path.
  1745. //
  1746. return STATUS_MORE_PROCESSING_REQUIRED;
  1747. } // end of ioctls to update capacity
  1748. }
  1749. if (retry && ((ULONG)(ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1)--) {
  1750. if (((ULONG)(ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1)) {
  1751. //
  1752. // Retry request.
  1753. //
  1754. TraceLog((CdromDebugWarning,
  1755. "Retry request %p - Calling StartIo\n", Irp));
  1756. ExFreePool(srb->SenseInfoBuffer);
  1757. if (srb->DataBuffer) {
  1758. ExFreePool(srb->DataBuffer);
  1759. }
  1760. ExFreePool(srb);
  1761. if (Irp->MdlAddress) {
  1762. IoFreeMdl(Irp->MdlAddress);
  1763. }
  1764. realIrpNextStack->Parameters.Others.Argument3 = (PVOID)-1;
  1765. IoFreeIrp(Irp);
  1766. CdRomRetryRequest(fdoExtension, realIrp, retryInterval, FALSE);
  1767. return STATUS_MORE_PROCESSING_REQUIRED;
  1768. }
  1769. //
  1770. // Exhausted retries. Fall through and complete the request with
  1771. // the appropriate status.
  1772. //
  1773. }
  1774. } else {
  1775. //
  1776. // Set status for successful request.
  1777. //
  1778. status = STATUS_SUCCESS;
  1779. }
  1780. if (NT_SUCCESS(status)) {
  1781. BOOLEAN b = FALSE;
  1782. switch (realIrpStack->Parameters.DeviceIoControl.IoControlCode) {
  1783. case IOCTL_DISK_VERIFY: {
  1784. //
  1785. // nothing to do but return the status...
  1786. //
  1787. break;
  1788. }
  1789. case IOCTL_STORAGE_SET_READ_AHEAD:
  1790. case IOCTL_CDROM_SET_VOLUME:
  1791. case IOCTL_DVD_END_SESSION:
  1792. case IOCTL_DVD_SEND_KEY:
  1793. case IOCTL_DVD_SEND_KEY2: {
  1794. //
  1795. // nothing to return
  1796. //
  1797. realIrp->IoStatus.Information = 0;
  1798. break;
  1799. }
  1800. case IOCTL_CDROM_PLAY_AUDIO_MSF: {
  1801. PLAY_ACTIVE(fdoExtension) = TRUE;
  1802. realIrp->IoStatus.Information = 0;
  1803. break;
  1804. }
  1805. case IOCTL_CDROM_STOP_AUDIO:
  1806. case IOCTL_CDROM_PAUSE_AUDIO: {
  1807. PLAY_ACTIVE(fdoExtension) = FALSE;
  1808. realIrp->IoStatus.Information = 0;
  1809. break;
  1810. }
  1811. case IOCTL_CDROM_SEEK_AUDIO_MSF:
  1812. case IOCTL_CDROM_RESUME_AUDIO: {
  1813. realIrp->IoStatus.Information = 0;
  1814. break;
  1815. }
  1816. case IOCTL_CDROM_GET_CONFIGURATION: {
  1817. RtlMoveMemory(realIrp->AssociatedIrp.SystemBuffer,
  1818. srb->DataBuffer,
  1819. srb->DataTransferLength);
  1820. realIrp->IoStatus.Information = srb->DataTransferLength;
  1821. break;
  1822. }
  1823. case IOCTL_DISK_GET_LENGTH_INFO: {
  1824. PGET_LENGTH_INFORMATION lengthInfo;
  1825. CdRomInterpretReadCapacity(DeviceObject,
  1826. (PREAD_CAPACITY_DATA)srb->DataBuffer);
  1827. lengthInfo = (PGET_LENGTH_INFORMATION)realIrp->AssociatedIrp.SystemBuffer;
  1828. lengthInfo->Length = commonExtension->PartitionLength;
  1829. realIrp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION);
  1830. status = STATUS_SUCCESS;
  1831. break;
  1832. }
  1833. case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX:
  1834. case IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX: {
  1835. PDISK_GEOMETRY_EX geometryEx;
  1836. CdRomInterpretReadCapacity(DeviceObject,
  1837. (PREAD_CAPACITY_DATA)srb->DataBuffer);
  1838. geometryEx = (PDISK_GEOMETRY_EX)(realIrp->AssociatedIrp.SystemBuffer);
  1839. geometryEx->DiskSize = commonExtension->PartitionLength;
  1840. geometryEx->Geometry = fdoExtension->DiskGeometry;
  1841. realIrp->IoStatus.Information =
  1842. FIELD_OFFSET(DISK_GEOMETRY_EX, Data);
  1843. break;
  1844. }
  1845. case IOCTL_DISK_GET_DRIVE_GEOMETRY:
  1846. case IOCTL_CDROM_GET_DRIVE_GEOMETRY: {
  1847. PDISK_GEOMETRY geometry;
  1848. CdRomInterpretReadCapacity(DeviceObject,
  1849. (PREAD_CAPACITY_DATA)srb->DataBuffer);
  1850. geometry = (PDISK_GEOMETRY)(realIrp->AssociatedIrp.SystemBuffer);
  1851. *geometry = fdoExtension->DiskGeometry;
  1852. realIrp->IoStatus.Information = sizeof(DISK_GEOMETRY);
  1853. break;
  1854. }
  1855. case IOCTL_DISK_CHECK_VERIFY:
  1856. case IOCTL_STORAGE_CHECK_VERIFY:
  1857. case IOCTL_CDROM_CHECK_VERIFY: {
  1858. if((realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_CHECK_VERIFY) &&
  1859. (realIrpStack->Parameters.DeviceIoControl.OutputBufferLength)) {
  1860. *((PULONG)realIrp->AssociatedIrp.SystemBuffer) =
  1861. commonExtension->PartitionZeroExtension->MediaChangeCount;
  1862. realIrp->IoStatus.Information = sizeof(ULONG);
  1863. } else {
  1864. realIrp->IoStatus.Information = 0;
  1865. }
  1866. TraceLog((CdromDebugTrace,
  1867. "CdRomDeviceControlCompletion: [%p] completing "
  1868. "CHECK_VERIFY buddy irp %p\n", realIrp, Irp));
  1869. break;
  1870. }
  1871. case IOCTL_CDROM_READ_TOC_EX: {
  1872. if (srb->DataTransferLength < MINIMUM_CDROM_READ_TOC_EX_SIZE) {
  1873. status = STATUS_INVALID_DEVICE_REQUEST;
  1874. break;
  1875. }
  1876. //
  1877. // Copy the returned info into the user buffer.
  1878. //
  1879. RtlMoveMemory(realIrp->AssociatedIrp.SystemBuffer,
  1880. srb->DataBuffer,
  1881. srb->DataTransferLength);
  1882. //
  1883. // update information field.
  1884. //
  1885. realIrp->IoStatus.Information = srb->DataTransferLength;
  1886. break;
  1887. }
  1888. case IOCTL_CDROM_GET_LAST_SESSION:
  1889. case IOCTL_CDROM_READ_TOC: {
  1890. //
  1891. // Copy the returned info into the user buffer.
  1892. //
  1893. RtlMoveMemory(realIrp->AssociatedIrp.SystemBuffer,
  1894. srb->DataBuffer,
  1895. srb->DataTransferLength);
  1896. //
  1897. // update information field.
  1898. //
  1899. realIrp->IoStatus.Information = srb->DataTransferLength;
  1900. break;
  1901. }
  1902. case IOCTL_DVD_READ_STRUCTURE: {
  1903. DVD_STRUCTURE_FORMAT format = ((PDVD_READ_STRUCTURE) realIrp->AssociatedIrp.SystemBuffer)->Format;
  1904. PDVD_DESCRIPTOR_HEADER header = realIrp->AssociatedIrp.SystemBuffer;
  1905. FOUR_BYTE fourByte = {0};
  1906. PTWO_BYTE twoByte;
  1907. UCHAR tmp;
  1908. TraceLog((CdromDebugTrace,
  1909. "DvdDeviceControlCompletion - IOCTL_DVD_READ_STRUCTURE: completing irp %p (buddy %p)\n",
  1910. Irp,
  1911. realIrp));
  1912. TraceLog((CdromDebugTrace,
  1913. "DvdDCCompletion - READ_STRUCTURE: descriptor format of %d\n", format));
  1914. RtlMoveMemory(header,
  1915. srb->DataBuffer,
  1916. srb->DataTransferLength);
  1917. //
  1918. // Cook the data. There are a number of fields that really
  1919. // should be byte-swapped for the caller.
  1920. //
  1921. TraceLog((CdromDebugInfo,
  1922. "DvdDCCompletion - READ_STRUCTURE:\n"
  1923. "\tHeader at %p\n"
  1924. "\tDvdDCCompletion - READ_STRUCTURE: data at %p\n"
  1925. "\tDataBuffer was at %p\n"
  1926. "\tDataTransferLength was %lx\n",
  1927. header,
  1928. header->Data,
  1929. srb->DataBuffer,
  1930. srb->DataTransferLength));
  1931. //
  1932. // First the fields in the header
  1933. //
  1934. TraceLog((CdromDebugInfo, "READ_STRUCTURE: header->Length %lx -> ",
  1935. header->Length));
  1936. REVERSE_SHORT(&header->Length);
  1937. TraceLog((CdromDebugInfo, "%lx\n", header->Length));
  1938. //
  1939. // Now the fields in the descriptor
  1940. //
  1941. if(format == DvdPhysicalDescriptor) {
  1942. PDVD_LAYER_DESCRIPTOR layer = (PDVD_LAYER_DESCRIPTOR) &(header->Data[0]);
  1943. TraceLog((CdromDebugInfo, "READ_STRUCTURE: StartingDataSector %lx -> ",
  1944. layer->StartingDataSector));
  1945. REVERSE_LONG(&(layer->StartingDataSector));
  1946. TraceLog((CdromDebugInfo, "%lx\n", layer->StartingDataSector));
  1947. TraceLog((CdromDebugInfo, "READ_STRUCTURE: EndDataSector %lx -> ",
  1948. layer->EndDataSector));
  1949. REVERSE_LONG(&(layer->EndDataSector));
  1950. TraceLog((CdromDebugInfo, "%lx\n", layer->EndDataSector));
  1951. TraceLog((CdromDebugInfo, "READ_STRUCTURE: EndLayerZeroSector %lx -> ",
  1952. layer->EndLayerZeroSector));
  1953. REVERSE_LONG(&(layer->EndLayerZeroSector));
  1954. TraceLog((CdromDebugInfo, "%lx\n", layer->EndLayerZeroSector));
  1955. }
  1956. TraceLog((CdromDebugTrace, "Status is %lx\n", Irp->IoStatus.Status));
  1957. TraceLog((CdromDebugTrace, "DvdDeviceControlCompletion - "
  1958. "IOCTL_DVD_READ_STRUCTURE: data transfer length of %d\n",
  1959. srb->DataTransferLength));
  1960. realIrp->IoStatus.Information = srb->DataTransferLength;
  1961. break;
  1962. }
  1963. case IOCTL_DVD_READ_KEY: {
  1964. PDVD_COPY_PROTECT_KEY copyProtectKey = realIrp->AssociatedIrp.SystemBuffer;
  1965. PCDVD_KEY_HEADER keyHeader = srb->DataBuffer;
  1966. ULONG dataLength;
  1967. ULONG transferLength =
  1968. srb->DataTransferLength -
  1969. FIELD_OFFSET(CDVD_KEY_HEADER, Data);
  1970. //
  1971. // Adjust the data length to ignore the two reserved bytes in the
  1972. // header.
  1973. //
  1974. dataLength = (keyHeader->DataLength[0] << 8) +
  1975. keyHeader->DataLength[1];
  1976. dataLength -= 2;
  1977. //
  1978. // take the minimum of the transferred length and the
  1979. // length as specified in the header.
  1980. //
  1981. if(dataLength < transferLength) {
  1982. transferLength = dataLength;
  1983. }
  1984. TraceLog((CdromDebugTrace,
  1985. "DvdDeviceControlCompletion: [%p] - READ_KEY with "
  1986. "transfer length of (%d or %d) bytes\n",
  1987. Irp,
  1988. dataLength,
  1989. srb->DataTransferLength - 2));
  1990. //
  1991. // Copy the key data into the return buffer
  1992. //
  1993. if(copyProtectKey->KeyType == DvdTitleKey) {
  1994. RtlMoveMemory(copyProtectKey->KeyData,
  1995. keyHeader->Data + 1,
  1996. transferLength - 1);
  1997. copyProtectKey->KeyData[transferLength - 1] = 0;
  1998. //
  1999. // If this is a title key then we need to copy the CGMS flags
  2000. // as well.
  2001. //
  2002. copyProtectKey->KeyFlags = *(keyHeader->Data);
  2003. } else {
  2004. RtlMoveMemory(copyProtectKey->KeyData,
  2005. keyHeader->Data,
  2006. transferLength);
  2007. }
  2008. copyProtectKey->KeyLength = sizeof(DVD_COPY_PROTECT_KEY);
  2009. copyProtectKey->KeyLength += transferLength;
  2010. realIrp->IoStatus.Information = copyProtectKey->KeyLength;
  2011. break;
  2012. }
  2013. case IOCTL_DVD_START_SESSION: {
  2014. PDVD_SESSION_ID sessionId = realIrp->AssociatedIrp.SystemBuffer;
  2015. PCDVD_KEY_HEADER keyHeader = srb->DataBuffer;
  2016. PCDVD_REPORT_AGID_DATA keyData = (PCDVD_REPORT_AGID_DATA) keyHeader->Data;
  2017. *sessionId = keyData->AGID;
  2018. realIrp->IoStatus.Information = sizeof(DVD_SESSION_ID);
  2019. break;
  2020. }
  2021. case IOCTL_CDROM_READ_Q_CHANNEL: {
  2022. PSUB_Q_CHANNEL_DATA userChannelData = realIrp->AssociatedIrp.SystemBuffer;
  2023. PCDROM_SUB_Q_DATA_FORMAT inputBuffer = realIrp->AssociatedIrp.SystemBuffer;
  2024. PSUB_Q_CHANNEL_DATA subQPtr = srb->DataBuffer;
  2025. #if DBG
  2026. switch( inputBuffer->Format ) {
  2027. case IOCTL_CDROM_CURRENT_POSITION:
  2028. TraceLog((CdromDebugTrace,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr->CurrentPosition.Header.AudioStatus ));
  2029. TraceLog((CdromDebugTrace,"CdRomDeviceControlCompletion: ADR = 0x%x\n", subQPtr->CurrentPosition.ADR ));
  2030. TraceLog((CdromDebugTrace,"CdRomDeviceControlCompletion: Control = 0x%x\n", subQPtr->CurrentPosition.Control ));
  2031. TraceLog((CdromDebugTrace,"CdRomDeviceControlCompletion: Track = %u\n", subQPtr->CurrentPosition.TrackNumber ));
  2032. TraceLog((CdromDebugTrace,"CdRomDeviceControlCompletion: Index = %u\n", subQPtr->CurrentPosition.IndexNumber ));
  2033. TraceLog((CdromDebugTrace,"CdRomDeviceControlCompletion: Absolute Address = %x\n", *((PULONG)subQPtr->CurrentPosition.AbsoluteAddress) ));
  2034. TraceLog((CdromDebugTrace,"CdRomDeviceControlCompletion: Relative Address = %x\n", *((PULONG)subQPtr->CurrentPosition.TrackRelativeAddress) ));
  2035. break;
  2036. case IOCTL_CDROM_MEDIA_CATALOG:
  2037. TraceLog((CdromDebugTrace,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr->MediaCatalog.Header.AudioStatus ));
  2038. TraceLog((CdromDebugTrace,"CdRomDeviceControlCompletion: Mcval is %u\n", subQPtr->MediaCatalog.Mcval ));
  2039. break;
  2040. case IOCTL_CDROM_TRACK_ISRC:
  2041. TraceLog((CdromDebugTrace,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr->TrackIsrc.Header.AudioStatus ));
  2042. TraceLog((CdromDebugTrace,"CdRomDeviceControlCompletion: Tcval is %u\n", subQPtr->TrackIsrc.Tcval ));
  2043. break;
  2044. }
  2045. #endif
  2046. //
  2047. // Update the play active status.
  2048. //
  2049. if (subQPtr->CurrentPosition.Header.AudioStatus == AUDIO_STATUS_IN_PROGRESS) {
  2050. PLAY_ACTIVE(fdoExtension) = TRUE;
  2051. } else {
  2052. PLAY_ACTIVE(fdoExtension) = FALSE;
  2053. }
  2054. //
  2055. // Check if output buffer is large enough to contain
  2056. // the data.
  2057. //
  2058. if (realIrpStack->Parameters.DeviceIoControl.OutputBufferLength <
  2059. srb->DataTransferLength) {
  2060. srb->DataTransferLength =
  2061. realIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
  2062. }
  2063. //
  2064. // Copy our buffer into users.
  2065. //
  2066. RtlMoveMemory(userChannelData,
  2067. subQPtr,
  2068. srb->DataTransferLength);
  2069. realIrp->IoStatus.Information = srb->DataTransferLength;
  2070. break;
  2071. }
  2072. case IOCTL_CDROM_GET_VOLUME: {
  2073. PAUDIO_OUTPUT audioOutput;
  2074. PVOLUME_CONTROL volumeControl = srb->DataBuffer;
  2075. ULONG i;
  2076. ULONG bytesTransferred;
  2077. audioOutput = ClassFindModePage((PCHAR)volumeControl,
  2078. srb->DataTransferLength,
  2079. CDROM_AUDIO_CONTROL_PAGE,
  2080. use6Byte);
  2081. //
  2082. // Verify the page is as big as expected.
  2083. //
  2084. bytesTransferred = (ULONG)((PCHAR) audioOutput - (PCHAR) volumeControl) +
  2085. sizeof(AUDIO_OUTPUT);
  2086. if (audioOutput != NULL &&
  2087. srb->DataTransferLength >= bytesTransferred) {
  2088. for (i=0; i<4; i++) {
  2089. volumeControl->PortVolume[i] =
  2090. audioOutput->PortOutput[i].Volume;
  2091. }
  2092. //
  2093. // Set bytes transferred in IRP.
  2094. //
  2095. realIrp->IoStatus.Information = sizeof(VOLUME_CONTROL);
  2096. } else {
  2097. realIrp->IoStatus.Information = 0;
  2098. status = STATUS_INVALID_DEVICE_REQUEST;
  2099. }
  2100. break;
  2101. }
  2102. default:
  2103. ASSERT(FALSE);
  2104. realIrp->IoStatus.Information = 0;
  2105. status = STATUS_INVALID_DEVICE_REQUEST;
  2106. } // end switch()
  2107. }
  2108. //
  2109. // Deallocate srb and sense buffer.
  2110. //
  2111. if (srb) {
  2112. if (srb->DataBuffer) {
  2113. ExFreePool(srb->DataBuffer);
  2114. }
  2115. if (srb->SenseInfoBuffer) {
  2116. ExFreePool(srb->SenseInfoBuffer);
  2117. }
  2118. ExFreePool(srb);
  2119. }
  2120. if (realIrp->PendingReturned) {
  2121. IoMarkIrpPending(realIrp);
  2122. }
  2123. if (Irp->MdlAddress) {
  2124. IoFreeMdl(Irp->MdlAddress);
  2125. }
  2126. IoFreeIrp(Irp);
  2127. //
  2128. // Set status in completing IRP.
  2129. //
  2130. realIrp->IoStatus.Status = status;
  2131. //
  2132. // Set the hard error if necessary.
  2133. //
  2134. if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
  2135. //
  2136. // Store DeviceObject for filesystem, and clear
  2137. // in IoStatus.Information field.
  2138. //
  2139. TraceLog((CdromDebugWarning,
  2140. "CdRomDeviceCompletion - Setting Hard Error on realIrp %p\n",
  2141. realIrp));
  2142. if (realIrp->Tail.Overlay.Thread) {
  2143. IoSetHardErrorOrVerifyDevice(realIrp, DeviceObject);
  2144. }
  2145. realIrp->IoStatus.Information = 0;
  2146. }
  2147. //
  2148. // note: must complete the realIrp, as the completed irp (above)
  2149. // was self-allocated.
  2150. //
  2151. CdRomCompleteIrpAndStartNextPacketSafely(DeviceObject, realIrp);
  2152. return STATUS_MORE_PROCESSING_REQUIRED;
  2153. }
  2154. NTSTATUS
  2155. CdRomSetVolumeIntermediateCompletion(
  2156. IN PDEVICE_OBJECT DeviceObject,
  2157. IN PIRP Irp,
  2158. IN PVOID Context
  2159. )
  2160. {
  2161. PFUNCTIONAL_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  2162. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  2163. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  2164. PCDROM_DATA cdData = (PCDROM_DATA)(commonExtension->DriverData);
  2165. BOOLEAN use6Byte = TEST_FLAG(cdData->XAFlags, XA_USE_6_BYTE);
  2166. PIO_STACK_LOCATION realIrpStack;
  2167. PIO_STACK_LOCATION realIrpNextStack;
  2168. PSCSI_REQUEST_BLOCK srb = Context;
  2169. PIRP realIrp = NULL;
  2170. NTSTATUS status;
  2171. BOOLEAN retry;
  2172. //
  2173. // Extract the 'real' irp from the irpstack.
  2174. //
  2175. realIrp = (PIRP) irpStack->Parameters.Others.Argument2;
  2176. realIrpStack = IoGetCurrentIrpStackLocation(realIrp);
  2177. realIrpNextStack = IoGetNextIrpStackLocation(realIrp);
  2178. //
  2179. // Check SRB status for success of completing request.
  2180. //
  2181. if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
  2182. ULONG retryInterval;
  2183. TraceLog((CdromDebugTrace,
  2184. "CdRomSetVolumeIntermediateCompletion: Irp %p, Srb %p, Real Irp %p\n",
  2185. Irp,
  2186. srb,
  2187. realIrp));
  2188. //
  2189. // Release the queue if it is frozen.
  2190. //
  2191. if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
  2192. ClassReleaseQueue(DeviceObject);
  2193. }
  2194. retry = ClassInterpretSenseInfo(DeviceObject,
  2195. srb,
  2196. irpStack->MajorFunction,
  2197. irpStack->Parameters.DeviceIoControl.IoControlCode,
  2198. MAXIMUM_RETRIES - ((ULONG)(ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1),
  2199. &status,
  2200. &retryInterval);
  2201. if (status == STATUS_DATA_OVERRUN) {
  2202. status = STATUS_SUCCESS;
  2203. retry = FALSE;
  2204. }
  2205. //
  2206. // If the status is verified required and the this request
  2207. // should bypass verify required then retry the request.
  2208. //
  2209. if (realIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
  2210. status == STATUS_VERIFY_REQUIRED) {
  2211. status = STATUS_IO_DEVICE_ERROR;
  2212. retry = TRUE;
  2213. }
  2214. if (retry && ((ULONG)(ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1)--) {
  2215. if (((ULONG)(ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1)) {
  2216. //
  2217. // Retry request.
  2218. //
  2219. TraceLog((CdromDebugWarning,
  2220. "Retry request %p - Calling StartIo\n", Irp));
  2221. ExFreePool(srb->SenseInfoBuffer);
  2222. ExFreePool(srb->DataBuffer);
  2223. ExFreePool(srb);
  2224. if (Irp->MdlAddress) {
  2225. IoFreeMdl(Irp->MdlAddress);
  2226. }
  2227. IoFreeIrp(Irp);
  2228. CdRomRetryRequest(deviceExtension,
  2229. realIrp,
  2230. retryInterval,
  2231. FALSE);
  2232. return STATUS_MORE_PROCESSING_REQUIRED;
  2233. }
  2234. //
  2235. // Exhausted retries. Fall through and complete the request with the appropriate status.
  2236. //
  2237. }
  2238. } else {
  2239. //
  2240. // Set status for successful request.
  2241. //
  2242. status = STATUS_SUCCESS;
  2243. }
  2244. if (NT_SUCCESS(status)) {
  2245. PAUDIO_OUTPUT audioInput = NULL;
  2246. PAUDIO_OUTPUT audioOutput;
  2247. PVOLUME_CONTROL volumeControl = realIrp->AssociatedIrp.SystemBuffer;
  2248. ULONG i,bytesTransferred,headerLength;
  2249. PVOID dataBuffer;
  2250. PCDB cdb;
  2251. audioInput = ClassFindModePage((PCHAR)srb->DataBuffer,
  2252. srb->DataTransferLength,
  2253. CDROM_AUDIO_CONTROL_PAGE,
  2254. use6Byte);
  2255. //
  2256. // Check to make sure the mode sense data is valid before we go on
  2257. //
  2258. if(audioInput == NULL) {
  2259. TraceLog((CdromDebugWarning,
  2260. "Mode Sense Page %d not found\n",
  2261. CDROM_AUDIO_CONTROL_PAGE));
  2262. realIrp->IoStatus.Information = 0;
  2263. realIrp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  2264. goto SafeExit;
  2265. }
  2266. if (use6Byte) {
  2267. headerLength = sizeof(MODE_PARAMETER_HEADER);
  2268. } else {
  2269. headerLength = sizeof(MODE_PARAMETER_HEADER10);
  2270. }
  2271. bytesTransferred = sizeof(AUDIO_OUTPUT) + headerLength;
  2272. //
  2273. // Allocate a new buffer for the mode select.
  2274. //
  2275. dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  2276. bytesTransferred,
  2277. CDROM_TAG_VOLUME_INT);
  2278. if (!dataBuffer) {
  2279. realIrp->IoStatus.Information = 0;
  2280. realIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  2281. goto SafeExit;
  2282. }
  2283. RtlZeroMemory(dataBuffer, bytesTransferred);
  2284. //
  2285. // Rebuild the data buffer to include the user requested values.
  2286. //
  2287. audioOutput = (PAUDIO_OUTPUT) ((PCHAR) dataBuffer + headerLength);
  2288. for (i=0; i<4; i++) {
  2289. audioOutput->PortOutput[i].Volume =
  2290. volumeControl->PortVolume[i];
  2291. audioOutput->PortOutput[i].ChannelSelection =
  2292. audioInput->PortOutput[i].ChannelSelection;
  2293. }
  2294. audioOutput->CodePage = CDROM_AUDIO_CONTROL_PAGE;
  2295. audioOutput->ParameterLength = sizeof(AUDIO_OUTPUT) - 2;
  2296. audioOutput->Immediate = MODE_SELECT_IMMEDIATE;
  2297. //
  2298. // Free the old data buffer, mdl.
  2299. //
  2300. IoFreeMdl(Irp->MdlAddress);
  2301. Irp->MdlAddress = NULL;
  2302. ExFreePool(srb->DataBuffer);
  2303. //
  2304. // set the data buffer to new allocation, so it can be
  2305. // freed in the exit path
  2306. //
  2307. srb->DataBuffer = dataBuffer;
  2308. //
  2309. // rebuild the srb.
  2310. //
  2311. cdb = (PCDB)srb->Cdb;
  2312. RtlZeroMemory(cdb, CDB12GENERIC_LENGTH);
  2313. srb->SrbStatus = srb->ScsiStatus = 0;
  2314. srb->SrbFlags = deviceExtension->SrbFlags;
  2315. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
  2316. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_OUT);
  2317. srb->DataTransferLength = bytesTransferred;
  2318. if (use6Byte) {
  2319. cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
  2320. cdb->MODE_SELECT.ParameterListLength = (UCHAR) bytesTransferred;
  2321. cdb->MODE_SELECT.PFBit = 1;
  2322. srb->CdbLength = 6;
  2323. } else {
  2324. cdb->MODE_SELECT10.OperationCode = SCSIOP_MODE_SELECT10;
  2325. cdb->MODE_SELECT10.ParameterListLength[0] = (UCHAR) (bytesTransferred >> 8);
  2326. cdb->MODE_SELECT10.ParameterListLength[1] = (UCHAR) (bytesTransferred & 0xFF);
  2327. cdb->MODE_SELECT10.PFBit = 1;
  2328. srb->CdbLength = 10;
  2329. }
  2330. //
  2331. // Prepare the MDL
  2332. //
  2333. Irp->MdlAddress = IoAllocateMdl(dataBuffer,
  2334. bytesTransferred,
  2335. FALSE,
  2336. FALSE,
  2337. (PIRP) NULL);
  2338. if (!Irp->MdlAddress) {
  2339. realIrp->IoStatus.Information = 0;
  2340. realIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  2341. goto SafeExit;
  2342. }
  2343. MmBuildMdlForNonPagedPool(Irp->MdlAddress);
  2344. irpStack = IoGetNextIrpStackLocation(Irp);
  2345. irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  2346. irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
  2347. irpStack->Parameters.Scsi.Srb = srb;
  2348. //
  2349. // reset the irp completion.
  2350. //
  2351. IoSetCompletionRoutine(Irp,
  2352. CdRomDeviceControlCompletion,
  2353. srb,
  2354. TRUE,
  2355. TRUE,
  2356. TRUE);
  2357. //
  2358. // Call the port driver.
  2359. //
  2360. IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  2361. return STATUS_MORE_PROCESSING_REQUIRED;
  2362. }
  2363. SafeExit:
  2364. //
  2365. // Deallocate srb and sense buffer.
  2366. //
  2367. if (srb) {
  2368. if (srb->DataBuffer) {
  2369. ExFreePool(srb->DataBuffer);
  2370. }
  2371. if (srb->SenseInfoBuffer) {
  2372. ExFreePool(srb->SenseInfoBuffer);
  2373. }
  2374. ExFreePool(srb);
  2375. }
  2376. if (Irp->PendingReturned) {
  2377. IoMarkIrpPending(Irp);
  2378. }
  2379. if (realIrp->PendingReturned) {
  2380. IoMarkIrpPending(realIrp);
  2381. }
  2382. if (Irp->MdlAddress) {
  2383. IoFreeMdl(Irp->MdlAddress);
  2384. }
  2385. IoFreeIrp(Irp);
  2386. //
  2387. // Set status in completing IRP.
  2388. //
  2389. realIrp->IoStatus.Status = status;
  2390. //
  2391. // Set the hard error if necessary.
  2392. //
  2393. if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
  2394. //
  2395. // Store DeviceObject for filesystem, and clear
  2396. // in IoStatus.Information field.
  2397. //
  2398. if (realIrp->Tail.Overlay.Thread) {
  2399. IoSetHardErrorOrVerifyDevice(realIrp, DeviceObject);
  2400. }
  2401. realIrp->IoStatus.Information = 0;
  2402. }
  2403. CdRomCompleteIrpAndStartNextPacketSafely(DeviceObject, realIrp);
  2404. return STATUS_MORE_PROCESSING_REQUIRED;
  2405. }
  2406. NTSTATUS
  2407. CdRomDvdEndAllSessionsCompletion(
  2408. IN PDEVICE_OBJECT DeviceObject,
  2409. IN PIRP Irp,
  2410. IN PVOID Context
  2411. )
  2412. /*++
  2413. Routine Description:
  2414. This routine will setup the next stack location to issue an end session
  2415. to the device. It will increment the session id in the system buffer
  2416. and issue an END_SESSION for that AGID if the AGID is valid.
  2417. When the new AGID is > 3 this routine will complete the request.
  2418. Arguments:
  2419. DeviceObject - the device object for this drive
  2420. Irp - the request
  2421. Context - done
  2422. Return Value:
  2423. STATUS_MORE_PROCESSING_REQUIRED if there is another AGID to clear
  2424. status otherwise.
  2425. --*/
  2426. {
  2427. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  2428. PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
  2429. PDVD_SESSION_ID sessionId = Irp->AssociatedIrp.SystemBuffer;
  2430. NTSTATUS status;
  2431. if(++(*sessionId) > MAX_COPY_PROTECT_AGID) {
  2432. //
  2433. // We're done here - just return success and let the io system
  2434. // continue to complete it.
  2435. //
  2436. return STATUS_SUCCESS;
  2437. }
  2438. IoCopyCurrentIrpStackLocationToNext(Irp);
  2439. IoSetCompletionRoutine(Irp,
  2440. CdRomDvdEndAllSessionsCompletion,
  2441. NULL,
  2442. TRUE,
  2443. FALSE,
  2444. FALSE);
  2445. IoMarkIrpPending(Irp);
  2446. IoCallDriver(fdoExtension->CommonExtension.DeviceObject, Irp);
  2447. //
  2448. // At this point we have to assume the irp may have already been
  2449. // completed. Ignore the returned status and return.
  2450. //
  2451. return STATUS_MORE_PROCESSING_REQUIRED;
  2452. }
  2453. NTSTATUS
  2454. CdRomDvdReadDiskKeyCompletion(
  2455. IN PDEVICE_OBJECT DeviceObject,
  2456. IN PIRP Irp,
  2457. IN PVOID Context
  2458. )
  2459. /*++
  2460. Routine Description:
  2461. This routine handles the completion of a request to obtain the disk
  2462. key from the dvd media. It will transform the raw 2K of key data into
  2463. a DVD_COPY_PROTECT_KEY structure and copy back the saved key parameters
  2464. from the context pointer before returning.
  2465. Arguments:
  2466. DeviceObject -
  2467. Irp -
  2468. Context - a DVD_COPY_PROTECT_KEY pointer which contains the key
  2469. parameters handed down by the caller.
  2470. Return Value:
  2471. STATUS_SUCCESS;
  2472. --*/
  2473. {
  2474. PDVD_COPY_PROTECT_KEY savedKey = Context;
  2475. PREAD_DVD_STRUCTURES_HEADER rawKey = Irp->AssociatedIrp.SystemBuffer;
  2476. PDVD_COPY_PROTECT_KEY outputKey = Irp->AssociatedIrp.SystemBuffer;
  2477. if (NT_SUCCESS(Irp->IoStatus.Status)) {
  2478. //
  2479. // Shift the data down to its new position.
  2480. //
  2481. RtlMoveMemory(outputKey->KeyData,
  2482. rawKey->Data,
  2483. sizeof(DVD_DISK_KEY_DESCRIPTOR));
  2484. RtlCopyMemory(outputKey,
  2485. savedKey,
  2486. sizeof(DVD_COPY_PROTECT_KEY));
  2487. outputKey->KeyLength = DVD_DISK_KEY_LENGTH;
  2488. Irp->IoStatus.Information = DVD_DISK_KEY_LENGTH;
  2489. } else {
  2490. TraceLog((CdromDebugWarning,
  2491. "DiskKey Failed with status %x, %p (%x) bytes\n",
  2492. Irp->IoStatus.Status,
  2493. (PVOID)Irp->IoStatus.Information,
  2494. ((rawKey->Length[0] << 16) | rawKey->Length[1])
  2495. ));
  2496. }
  2497. //
  2498. // release the context block
  2499. //
  2500. ExFreePool(Context);
  2501. return STATUS_SUCCESS;
  2502. }
  2503. NTSTATUS
  2504. CdRomXACompletion(
  2505. IN PDEVICE_OBJECT DeviceObject,
  2506. IN PIRP Irp,
  2507. IN PVOID Context
  2508. )
  2509. /*++
  2510. Routine Description:
  2511. This routine executes when the port driver has completed a request.
  2512. It looks at the SRB status in the completing SRB and if not success
  2513. it checks for valid request sense buffer information. If valid, the
  2514. info is used to update status with more precise message of type of
  2515. error. This routine deallocates the SRB.
  2516. Arguments:
  2517. DeviceObject - Supplies the device object which represents the logical
  2518. unit.
  2519. Irp - Supplies the Irp which has completed.
  2520. Context - Supplies a pointer to the SRB.
  2521. Return Value:
  2522. NT status
  2523. --*/
  2524. {
  2525. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  2526. PSCSI_REQUEST_BLOCK srb = Context;
  2527. PFUNCTIONAL_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  2528. NTSTATUS status;
  2529. BOOLEAN retry;
  2530. //
  2531. // Check SRB status for success of completing request.
  2532. //
  2533. if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
  2534. ULONG retryInterval;
  2535. TraceLog((CdromDebugTrace, "CdromXAComplete: IRP %p SRB %p Status %x\n",
  2536. Irp, srb, srb->SrbStatus));
  2537. //
  2538. // Release the queue if it is frozen.
  2539. //
  2540. if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
  2541. ClassReleaseQueue(DeviceObject);
  2542. }
  2543. retry = ClassInterpretSenseInfo(
  2544. DeviceObject,
  2545. srb,
  2546. irpStack->MajorFunction,
  2547. irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL ? irpStack->Parameters.DeviceIoControl.IoControlCode : 0,
  2548. MAXIMUM_RETRIES - irpStack->MinorFunction, // HACKHACK - REF #0001
  2549. &status,
  2550. &retryInterval);
  2551. //
  2552. // If the status is verified required and the this request
  2553. // should bypass verify required then retry the request.
  2554. //
  2555. if (irpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
  2556. status == STATUS_VERIFY_REQUIRED) {
  2557. status = STATUS_IO_DEVICE_ERROR;
  2558. retry = TRUE;
  2559. }
  2560. if (retry) {
  2561. if (irpStack->MinorFunction != 0) { // HACKHACK - REF #0001
  2562. irpStack->MinorFunction--; // HACKHACK - REF #0001
  2563. //
  2564. // Retry request.
  2565. //
  2566. TraceLog((CdromDebugWarning,
  2567. "CdRomXACompletion: Retry request %p (%x) - "
  2568. "Calling StartIo\n", Irp, irpStack->MinorFunction));
  2569. ExFreePool(srb->SenseInfoBuffer);
  2570. ExFreePool(srb);
  2571. //
  2572. // Call StartIo directly since IoStartNextPacket hasn't been called,
  2573. // the serialisation is still intact.
  2574. //
  2575. CdRomRetryRequest(deviceExtension,
  2576. Irp,
  2577. retryInterval,
  2578. FALSE);
  2579. return STATUS_MORE_PROCESSING_REQUIRED;
  2580. }
  2581. //
  2582. // Exhausted retries, fall through and complete the request
  2583. // with the appropriate status
  2584. //
  2585. TraceLog((CdromDebugWarning,
  2586. "CdRomXACompletion: Retries exhausted for irp %p\n",
  2587. Irp));
  2588. }
  2589. } else {
  2590. //
  2591. // Set status for successful request.
  2592. //
  2593. status = STATUS_SUCCESS;
  2594. } // end if (SRB_STATUS(srb->SrbStatus) ...
  2595. //
  2596. // Return SRB to nonpaged pool.
  2597. //
  2598. ExFreePool(srb->SenseInfoBuffer);
  2599. ExFreePool(srb);
  2600. //
  2601. // Set status in completing IRP.
  2602. //
  2603. Irp->IoStatus.Status = status;
  2604. //
  2605. // Set the hard error if necessary.
  2606. //
  2607. if (!NT_SUCCESS(status) &&
  2608. IoIsErrorUserInduced(status) &&
  2609. Irp->Tail.Overlay.Thread != NULL ) {
  2610. //
  2611. // Store DeviceObject for filesystem, and clear
  2612. // in IoStatus.Information field.
  2613. //
  2614. IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
  2615. Irp->IoStatus.Information = 0;
  2616. }
  2617. //
  2618. // If pending has be returned for this irp then mark the current stack as
  2619. // pending.
  2620. //
  2621. if (Irp->PendingReturned) {
  2622. IoMarkIrpPending(Irp);
  2623. }
  2624. {
  2625. KIRQL oldIrql = KeRaiseIrqlToDpcLevel();
  2626. IoStartNextPacket(DeviceObject, FALSE);
  2627. KeLowerIrql(oldIrql);
  2628. }
  2629. ClassReleaseRemoveLock(DeviceObject, Irp);
  2630. return status;
  2631. }
  2632. VOID
  2633. CdRomDeviceControlDvdReadStructure(
  2634. IN PDEVICE_OBJECT Fdo,
  2635. IN PIRP OriginalIrp,
  2636. IN PIRP NewIrp,
  2637. IN PSCSI_REQUEST_BLOCK Srb
  2638. )
  2639. {
  2640. PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(OriginalIrp);
  2641. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  2642. PCDB cdb = (PCDB)Srb->Cdb;
  2643. PVOID dataBuffer;
  2644. PDVD_READ_STRUCTURE request;
  2645. USHORT dataLength;
  2646. ULONG blockNumber;
  2647. PFOUR_BYTE fourByte;
  2648. dataLength =
  2649. (USHORT)currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
  2650. request = OriginalIrp->AssociatedIrp.SystemBuffer;
  2651. blockNumber =
  2652. (ULONG)(request->BlockByteOffset.QuadPart >> fdoExtension->SectorShift);
  2653. fourByte = (PFOUR_BYTE) &blockNumber;
  2654. Srb->CdbLength = 12;
  2655. Srb->TimeOutValue = fdoExtension->TimeOutValue;
  2656. Srb->SrbFlags = fdoExtension->SrbFlags;
  2657. SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DATA_IN);
  2658. cdb->READ_DVD_STRUCTURE.OperationCode = SCSIOP_READ_DVD_STRUCTURE;
  2659. cdb->READ_DVD_STRUCTURE.RMDBlockNumber[0] = fourByte->Byte3;
  2660. cdb->READ_DVD_STRUCTURE.RMDBlockNumber[1] = fourByte->Byte2;
  2661. cdb->READ_DVD_STRUCTURE.RMDBlockNumber[2] = fourByte->Byte1;
  2662. cdb->READ_DVD_STRUCTURE.RMDBlockNumber[3] = fourByte->Byte0;
  2663. cdb->READ_DVD_STRUCTURE.LayerNumber = request->LayerNumber;
  2664. cdb->READ_DVD_STRUCTURE.Format = (UCHAR)request->Format;
  2665. #if DBG
  2666. {
  2667. if ((UCHAR)request->Format > DvdMaxDescriptor) {
  2668. TraceLog((CdromDebugWarning,
  2669. "READ_DVD_STRUCTURE format %x = %s (%x bytes)\n",
  2670. (UCHAR)request->Format,
  2671. READ_DVD_STRUCTURE_FORMAT_STRINGS[DvdMaxDescriptor],
  2672. dataLength
  2673. ));
  2674. } else {
  2675. TraceLog((CdromDebugWarning,
  2676. "READ_DVD_STRUCTURE format %x = %s (%x bytes)\n",
  2677. (UCHAR)request->Format,
  2678. READ_DVD_STRUCTURE_FORMAT_STRINGS[(UCHAR)request->Format],
  2679. dataLength
  2680. ));
  2681. }
  2682. }
  2683. #endif // DBG
  2684. if (request->Format == DvdDiskKeyDescriptor) {
  2685. cdb->READ_DVD_STRUCTURE.AGID = (UCHAR) request->SessionId;
  2686. }
  2687. cdb->READ_DVD_STRUCTURE.AllocationLength[0] = (UCHAR)(dataLength >> 8);
  2688. cdb->READ_DVD_STRUCTURE.AllocationLength[1] = (UCHAR)(dataLength & 0xff);
  2689. Srb->DataTransferLength = dataLength;
  2690. dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  2691. dataLength,
  2692. DVD_TAG_READ_STRUCTURE);
  2693. if (!dataBuffer) {
  2694. ExFreePool(Srb->SenseInfoBuffer);
  2695. ExFreePool(Srb);
  2696. IoFreeIrp(NewIrp);
  2697. OriginalIrp->IoStatus.Information = 0;
  2698. OriginalIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  2699. BAIL_OUT(OriginalIrp);
  2700. CdRomCompleteIrpAndStartNextPacketSafely(Fdo, OriginalIrp);
  2701. return;
  2702. }
  2703. /*
  2704. * Zero out input buffer in case the device returns fewer bytes than advertized,
  2705. * which would cause us to return uninitialized kernel memory.
  2706. */
  2707. RtlZeroMemory(dataBuffer, dataLength);
  2708. NewIrp->MdlAddress = IoAllocateMdl(dataBuffer,
  2709. currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength,
  2710. FALSE,
  2711. FALSE,
  2712. (PIRP) NULL);
  2713. if (NewIrp->MdlAddress == NULL) {
  2714. ExFreePool(dataBuffer);
  2715. ExFreePool(Srb->SenseInfoBuffer);
  2716. ExFreePool(Srb);
  2717. IoFreeIrp(NewIrp);
  2718. OriginalIrp->IoStatus.Information = 0;
  2719. OriginalIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  2720. BAIL_OUT(OriginalIrp);
  2721. CdRomCompleteIrpAndStartNextPacketSafely(Fdo, OriginalIrp);
  2722. return;
  2723. }
  2724. //
  2725. // Prepare the MDL
  2726. //
  2727. MmBuildMdlForNonPagedPool(NewIrp->MdlAddress);
  2728. Srb->DataBuffer = dataBuffer;
  2729. IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, NewIrp);
  2730. return;
  2731. }
  2732. VOID
  2733. CdRomDeviceControlDvdEndSession(
  2734. IN PDEVICE_OBJECT Fdo,
  2735. IN PIRP OriginalIrp,
  2736. IN PIRP NewIrp,
  2737. IN PSCSI_REQUEST_BLOCK Srb
  2738. )
  2739. {
  2740. PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(OriginalIrp);
  2741. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  2742. PCDB cdb = (PCDB)Srb->Cdb;
  2743. PDVD_SESSION_ID sessionId = OriginalIrp->AssociatedIrp.SystemBuffer;
  2744. Srb->CdbLength = 12;
  2745. Srb->TimeOutValue = fdoExtension->TimeOutValue;
  2746. Srb->SrbFlags = fdoExtension->SrbFlags;
  2747. SET_FLAG(Srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER);
  2748. cdb->SEND_KEY.OperationCode = SCSIOP_SEND_KEY;
  2749. cdb->SEND_KEY.AGID = (UCHAR) (*sessionId);
  2750. cdb->SEND_KEY.KeyFormat = DVD_INVALIDATE_AGID;
  2751. IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, NewIrp);
  2752. return;
  2753. }
  2754. VOID
  2755. CdRomDeviceControlDvdStartSessionReadKey(
  2756. IN PDEVICE_OBJECT Fdo,
  2757. IN PIRP OriginalIrp,
  2758. IN PIRP NewIrp,
  2759. IN PSCSI_REQUEST_BLOCK Srb
  2760. )
  2761. {
  2762. PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(OriginalIrp);
  2763. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  2764. PCDB cdb = (PCDB)Srb->Cdb;
  2765. NTSTATUS status;
  2766. PDVD_COPY_PROTECT_KEY keyParameters;
  2767. PCDVD_KEY_HEADER keyBuffer = NULL;
  2768. ULONG keyLength;
  2769. ULONG allocationLength;
  2770. PFOUR_BYTE fourByte;
  2771. //
  2772. // Both of these use REPORT_KEY commands.
  2773. // Determine the size of the input buffer
  2774. //
  2775. if(currentIrpStack->Parameters.DeviceIoControl.IoControlCode ==
  2776. IOCTL_DVD_READ_KEY) {
  2777. keyParameters = OriginalIrp->AssociatedIrp.SystemBuffer;
  2778. keyLength = sizeof(CDVD_KEY_HEADER) +
  2779. (currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength -
  2780. sizeof(DVD_COPY_PROTECT_KEY));
  2781. } else {
  2782. keyParameters = NULL;
  2783. keyLength = sizeof(CDVD_KEY_HEADER) +
  2784. sizeof(CDVD_REPORT_AGID_DATA);
  2785. }
  2786. TRY {
  2787. keyBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  2788. keyLength,
  2789. DVD_TAG_READ_KEY);
  2790. if(keyBuffer == NULL) {
  2791. TraceLog((CdromDebugWarning,
  2792. "IOCTL_DVD_READ_KEY - couldn't allocate "
  2793. "%d byte buffer for key\n",
  2794. keyLength));
  2795. status = STATUS_INSUFFICIENT_RESOURCES;
  2796. LEAVE;
  2797. }
  2798. NewIrp->MdlAddress = IoAllocateMdl(keyBuffer,
  2799. keyLength,
  2800. FALSE,
  2801. FALSE,
  2802. (PIRP) NULL);
  2803. if(NewIrp->MdlAddress == NULL) {
  2804. TraceLog((CdromDebugWarning,
  2805. "IOCTL_DVD_READ_KEY - couldn't create mdl\n"));
  2806. status = STATUS_INSUFFICIENT_RESOURCES;
  2807. LEAVE;
  2808. }
  2809. MmBuildMdlForNonPagedPool(NewIrp->MdlAddress);
  2810. Srb->DataBuffer = keyBuffer;
  2811. Srb->CdbLength = 12;
  2812. cdb->REPORT_KEY.OperationCode = SCSIOP_REPORT_KEY;
  2813. allocationLength = keyLength;
  2814. fourByte = (PFOUR_BYTE) &allocationLength;
  2815. cdb->REPORT_KEY.AllocationLength[0] = fourByte->Byte1;
  2816. cdb->REPORT_KEY.AllocationLength[1] = fourByte->Byte0;
  2817. Srb->DataTransferLength = keyLength;
  2818. //
  2819. // set the specific parameters....
  2820. //
  2821. if(currentIrpStack->Parameters.DeviceIoControl.IoControlCode ==
  2822. IOCTL_DVD_READ_KEY) {
  2823. if(keyParameters->KeyType == DvdTitleKey) {
  2824. ULONG logicalBlockAddress;
  2825. logicalBlockAddress = (ULONG)
  2826. (keyParameters->Parameters.TitleOffset.QuadPart >>
  2827. fdoExtension->SectorShift);
  2828. fourByte = (PFOUR_BYTE) &(logicalBlockAddress);
  2829. cdb->REPORT_KEY.LogicalBlockAddress[0] = fourByte->Byte3;
  2830. cdb->REPORT_KEY.LogicalBlockAddress[1] = fourByte->Byte2;
  2831. cdb->REPORT_KEY.LogicalBlockAddress[2] = fourByte->Byte1;
  2832. cdb->REPORT_KEY.LogicalBlockAddress[3] = fourByte->Byte0;
  2833. }
  2834. cdb->REPORT_KEY.KeyFormat = (UCHAR)keyParameters->KeyType;
  2835. cdb->REPORT_KEY.AGID = (UCHAR) keyParameters->SessionId;
  2836. TraceLog((CdromDebugWarning,
  2837. "CdRomDvdReadKey => sending irp %p for irp %p (%s)\n",
  2838. NewIrp, OriginalIrp, "READ_KEY"));
  2839. } else {
  2840. cdb->REPORT_KEY.KeyFormat = DVD_REPORT_AGID;
  2841. cdb->REPORT_KEY.AGID = 0;
  2842. TraceLog((CdromDebugWarning,
  2843. "CdRomDvdReadKey => sending irp %p for irp %p (%s)\n",
  2844. NewIrp, OriginalIrp, "START_SESSION"));
  2845. }
  2846. Srb->TimeOutValue = fdoExtension->TimeOutValue;
  2847. Srb->SrbFlags = fdoExtension->SrbFlags;
  2848. SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DATA_IN);
  2849. IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, NewIrp);
  2850. status = STATUS_SUCCESS;
  2851. } FINALLY {
  2852. if (!NT_SUCCESS(status)) {
  2853. //
  2854. // An error occured during setup - free resources and
  2855. // complete this request.
  2856. //
  2857. if (NewIrp->MdlAddress != NULL) {
  2858. IoFreeMdl(NewIrp->MdlAddress);
  2859. }
  2860. if (keyBuffer != NULL) {
  2861. ExFreePool(keyBuffer);
  2862. }
  2863. ExFreePool(Srb->SenseInfoBuffer);
  2864. ExFreePool(Srb);
  2865. IoFreeIrp(NewIrp);
  2866. OriginalIrp->IoStatus.Information = 0;
  2867. OriginalIrp->IoStatus.Status = status;
  2868. BAIL_OUT(OriginalIrp);
  2869. CdRomCompleteIrpAndStartNextPacketSafely(Fdo, OriginalIrp);
  2870. } // end !NT_SUCCESS
  2871. }
  2872. return;
  2873. }
  2874. VOID
  2875. CdRomDeviceControlDvdSendKey(
  2876. IN PDEVICE_OBJECT Fdo,
  2877. IN PIRP OriginalIrp,
  2878. IN PIRP NewIrp,
  2879. IN PSCSI_REQUEST_BLOCK Srb
  2880. )
  2881. {
  2882. PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(OriginalIrp);
  2883. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  2884. PCDB cdb = (PCDB)Srb->Cdb;
  2885. PDVD_COPY_PROTECT_KEY key;
  2886. PCDVD_KEY_HEADER keyBuffer = NULL;
  2887. NTSTATUS status;
  2888. ULONG keyLength;
  2889. PFOUR_BYTE fourByte;
  2890. key = OriginalIrp->AssociatedIrp.SystemBuffer;
  2891. keyLength = (key->KeyLength - sizeof(DVD_COPY_PROTECT_KEY)) +
  2892. sizeof(CDVD_KEY_HEADER);
  2893. TRY {
  2894. keyBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  2895. keyLength,
  2896. DVD_TAG_SEND_KEY);
  2897. if(keyBuffer == NULL) {
  2898. TraceLog((CdromDebugWarning,
  2899. "IOCTL_DVD_SEND_KEY - couldn't allocate "
  2900. "%d byte buffer for key\n",
  2901. keyLength));
  2902. status = STATUS_INSUFFICIENT_RESOURCES;
  2903. LEAVE;
  2904. }
  2905. RtlZeroMemory(keyBuffer, keyLength);
  2906. //
  2907. // keylength is decremented here by two because the
  2908. // datalength does not include the header, which is two
  2909. // bytes. keylength is immediately incremented later
  2910. // by the same amount.
  2911. //
  2912. keyLength -= 2;
  2913. fourByte = (PFOUR_BYTE) &keyLength;
  2914. keyBuffer->DataLength[0] = fourByte->Byte1;
  2915. keyBuffer->DataLength[1] = fourByte->Byte0;
  2916. keyLength += 2;
  2917. //
  2918. // copy the user's buffer to our own allocated buffer
  2919. //
  2920. RtlMoveMemory(keyBuffer->Data,
  2921. key->KeyData,
  2922. key->KeyLength - sizeof(DVD_COPY_PROTECT_KEY));
  2923. NewIrp->MdlAddress = IoAllocateMdl(keyBuffer,
  2924. keyLength,
  2925. FALSE,
  2926. FALSE,
  2927. (PIRP) NULL);
  2928. if(NewIrp->MdlAddress == NULL) {
  2929. TraceLog((CdromDebugWarning,
  2930. "IOCTL_DVD_SEND_KEY - couldn't create mdl\n"));
  2931. status = STATUS_INSUFFICIENT_RESOURCES;
  2932. LEAVE;
  2933. }
  2934. MmBuildMdlForNonPagedPool(NewIrp->MdlAddress);
  2935. Srb->CdbLength = 12;
  2936. Srb->DataBuffer = keyBuffer;
  2937. Srb->DataTransferLength = keyLength;
  2938. Srb->TimeOutValue = fdoExtension->TimeOutValue;
  2939. Srb->SrbFlags = fdoExtension->SrbFlags;
  2940. SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DATA_OUT);
  2941. cdb->REPORT_KEY.OperationCode = SCSIOP_SEND_KEY;
  2942. fourByte = (PFOUR_BYTE) &keyLength;
  2943. cdb->SEND_KEY.ParameterListLength[0] = fourByte->Byte1;
  2944. cdb->SEND_KEY.ParameterListLength[1] = fourByte->Byte0;
  2945. cdb->SEND_KEY.KeyFormat = (UCHAR)key->KeyType;
  2946. cdb->SEND_KEY.AGID = (UCHAR) key->SessionId;
  2947. if (key->KeyType == DvdSetRpcKey) {
  2948. TraceLog((CdromDebugWarning,
  2949. "IOCTL_DVD_SEND_KEY - Setting RPC2 drive region\n"));
  2950. } else {
  2951. TraceLog((CdromDebugWarning,
  2952. "IOCTL_DVD_SEND_KEY - key type %x\n", key->KeyType));
  2953. }
  2954. IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, NewIrp);
  2955. status = STATUS_SUCCESS;
  2956. } FINALLY {
  2957. if (!NT_SUCCESS(status)) {
  2958. //
  2959. // An error occured during setup - free resources and
  2960. // complete this request.
  2961. //
  2962. if (NewIrp->MdlAddress != NULL) {
  2963. IoFreeMdl(NewIrp->MdlAddress);
  2964. }
  2965. if (keyBuffer != NULL) {
  2966. ExFreePool(keyBuffer);
  2967. }
  2968. ExFreePool(Srb->SenseInfoBuffer);
  2969. ExFreePool(Srb);
  2970. IoFreeIrp(NewIrp);
  2971. OriginalIrp->IoStatus.Information = 0;
  2972. OriginalIrp->IoStatus.Status = status;
  2973. BAIL_OUT(OriginalIrp);
  2974. CdRomCompleteIrpAndStartNextPacketSafely(Fdo, OriginalIrp);
  2975. }
  2976. }
  2977. return;
  2978. }
  2979. VOID
  2980. CdRomInterpretReadCapacity(
  2981. IN PDEVICE_OBJECT Fdo,
  2982. IN PREAD_CAPACITY_DATA ReadCapacityBuffer
  2983. )
  2984. {
  2985. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  2986. PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
  2987. ULONG lastSector;
  2988. ULONG bps;
  2989. ULONG lastBit;
  2990. ULONG tmp;
  2991. ASSERT(ReadCapacityBuffer);
  2992. ASSERT(commonExtension->IsFdo);
  2993. TraceLog((CdromDebugError,
  2994. "CdRomInterpretReadCapacity: Entering\n"));
  2995. //
  2996. // Swizzle bytes from Read Capacity and translate into
  2997. // the necessary geometry information in the device extension.
  2998. //
  2999. tmp = ReadCapacityBuffer->BytesPerBlock;
  3000. ((PFOUR_BYTE)&bps)->Byte0 = ((PFOUR_BYTE)&tmp)->Byte3;
  3001. ((PFOUR_BYTE)&bps)->Byte1 = ((PFOUR_BYTE)&tmp)->Byte2;
  3002. ((PFOUR_BYTE)&bps)->Byte2 = ((PFOUR_BYTE)&tmp)->Byte1;
  3003. ((PFOUR_BYTE)&bps)->Byte3 = ((PFOUR_BYTE)&tmp)->Byte0;
  3004. //
  3005. // Insure that bps is a power of 2.
  3006. // This corrects a problem with the HP 4020i CDR where it
  3007. // returns an incorrect number for bytes per sector.
  3008. //
  3009. if (!bps) {
  3010. bps = 2048;
  3011. } else {
  3012. lastBit = (ULONG) -1;
  3013. while (bps) {
  3014. lastBit++;
  3015. bps = bps >> 1;
  3016. }
  3017. bps = 1 << lastBit;
  3018. }
  3019. fdoExtension->DiskGeometry.BytesPerSector = bps;
  3020. TraceLog((CdromDebugTrace, "CdRomInterpretReadCapacity: Calculated bps %#x\n",
  3021. fdoExtension->DiskGeometry.BytesPerSector));
  3022. //
  3023. // Copy last sector in reverse byte order.
  3024. //
  3025. tmp = ReadCapacityBuffer->LogicalBlockAddress;
  3026. ((PFOUR_BYTE)&lastSector)->Byte0 = ((PFOUR_BYTE)&tmp)->Byte3;
  3027. ((PFOUR_BYTE)&lastSector)->Byte1 = ((PFOUR_BYTE)&tmp)->Byte2;
  3028. ((PFOUR_BYTE)&lastSector)->Byte2 = ((PFOUR_BYTE)&tmp)->Byte1;
  3029. ((PFOUR_BYTE)&lastSector)->Byte3 = ((PFOUR_BYTE)&tmp)->Byte0;
  3030. //
  3031. // Calculate sector to byte shift.
  3032. //
  3033. WHICH_BIT(bps, fdoExtension->SectorShift);
  3034. TraceLog((CdromDebugTrace,"CdRomInterpretReadCapacity: Sector size is %d\n",
  3035. fdoExtension->DiskGeometry.BytesPerSector));
  3036. TraceLog((CdromDebugTrace,"CdRomInterpretReadCapacity: Number of Sectors is %d\n",
  3037. lastSector + 1));
  3038. //
  3039. // Calculate media capacity in bytes.
  3040. //
  3041. commonExtension->PartitionLength.QuadPart = (LONGLONG)(lastSector + 1);
  3042. //
  3043. // we've defaulted to 32/64 forever. don't want to change this now...
  3044. //
  3045. fdoExtension->DiskGeometry.TracksPerCylinder = 0x40;
  3046. fdoExtension->DiskGeometry.SectorsPerTrack = 0x20;
  3047. //
  3048. // Calculate number of cylinders.
  3049. //
  3050. fdoExtension->DiskGeometry.Cylinders.QuadPart = (LONGLONG)((lastSector + 1) / (32 * 64));
  3051. commonExtension->PartitionLength.QuadPart =
  3052. (commonExtension->PartitionLength.QuadPart << fdoExtension->SectorShift);
  3053. ASSERT(TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA));
  3054. //
  3055. // This device supports removable media.
  3056. //
  3057. fdoExtension->DiskGeometry.MediaType = RemovableMedia;
  3058. return;
  3059. }