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

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