* Sync up to trunk head (r64377).
[reactos.git] / drivers / storage / class / cdrom_new / ioctl.c
1 /*--
2
3 Copyright (C) Microsoft Corporation, 1999 - 1999
4
5 Module Name:
6
7 ioctl.c
8
9 Abstract:
10
11 The CDROM class driver tranlates IRPs to SRBs with embedded CDBs
12 and sends them to its devices through the port driver.
13
14 Environment:
15
16 kernel mode only
17
18 Notes:
19
20 SCSI Tape, CDRom and Disk class drivers share common routines
21 that can be found in the CLASS directory (..\ntos\dd\class).
22
23 Revision History:
24
25 --*/
26
27 #include "cdrom.h"
28
29 #if DBG
30 PUCHAR READ_DVD_STRUCTURE_FORMAT_STRINGS[DvdMaxDescriptor+1] = {
31 "Physical",
32 "Copyright",
33 "DiskKey",
34 "BCA",
35 "Manufacturer",
36 "Unknown"
37 };
38 #endif // DBG
39
40 #define DEFAULT_CDROM_SECTORS_PER_TRACK 32
41 #define DEFAULT_TRACKS_PER_CYLINDER 64
42
43 NTSTATUS
44 NTAPI
45 CdRomDeviceControlDispatch(
46 IN PDEVICE_OBJECT DeviceObject,
47 IN PIRP Irp
48 )
49 /*++
50
51 Routine Description:
52
53 This is the NT device control handler for CDROMs.
54
55 Arguments:
56
57 DeviceObject - for this CDROM
58
59 Irp - IO Request packet
60
61 Return Value:
62
63 NTSTATUS
64
65 --*/
66 {
67 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
68 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
69
70 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
71 PIO_STACK_LOCATION nextStack;
72 PCDROM_DATA cdData = (PCDROM_DATA)(commonExtension->DriverData);
73
74 BOOLEAN use6Byte = TEST_FLAG(cdData->XAFlags, XA_USE_6_BYTE);
75 SCSI_REQUEST_BLOCK srb;
76 PCDB cdb = (PCDB)srb.Cdb;
77 //PVOID outputBuffer;
78 ULONG bytesTransferred = 0;
79 NTSTATUS status;
80 //NTSTATUS status2;
81 KIRQL irql;
82
83 ULONG ioctlCode;
84 ULONG baseCode;
85 ULONG functionCode;
86
87 RetryControl:
88
89 //
90 // Zero the SRB on stack.
91 //
92
93 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
94
95 Irp->IoStatus.Information = 0;
96
97 //
98 // if this is a class driver ioctl then we need to change the base code
99 // to IOCTL_CDROM_BASE so that the switch statement can handle it.
100 //
101 // WARNING - currently the scsi class ioctl function codes are between
102 // 0x200 & 0x300. this routine depends on that fact
103 //
104
105 ioctlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
106 baseCode = ioctlCode >> 16;
107 functionCode = (ioctlCode & (~0xffffc003)) >> 2;
108
109 TraceLog((CdromDebugTrace,
110 "CdRomDeviceControl: Ioctl Code = %lx, Base Code = %lx,"
111 " Function Code = %lx\n",
112 ioctlCode,
113 baseCode,
114 functionCode
115 ));
116
117 if((functionCode >= 0x200) && (functionCode <= 0x300)) {
118
119 ioctlCode = (ioctlCode & 0x0000ffff) | CTL_CODE(IOCTL_CDROM_BASE, 0, 0, 0);
120
121 TraceLog((CdromDebugTrace,
122 "CdRomDeviceControl: Class Code - new ioctl code is %lx\n",
123 ioctlCode));
124
125 irpStack->Parameters.DeviceIoControl.IoControlCode = ioctlCode;
126
127 }
128
129 switch (ioctlCode) {
130
131 case IOCTL_STORAGE_GET_MEDIA_TYPES_EX: {
132
133 PGET_MEDIA_TYPES mediaTypes = Irp->AssociatedIrp.SystemBuffer;
134 PDEVICE_MEDIA_INFO mediaInfo = &mediaTypes->MediaInfo[0];
135 ULONG sizeNeeded;
136
137 sizeNeeded = sizeof(GET_MEDIA_TYPES);
138
139 //
140 // IsMmc is static...
141 //
142
143 if (cdData->Mmc.IsMmc) {
144 sizeNeeded += sizeof(DEVICE_MEDIA_INFO) * 1; // return two media types
145 }
146
147 //
148 // Ensure that buffer is large enough.
149 //
150
151 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
152 sizeNeeded) {
153
154 //
155 // Buffer too small.
156 //
157
158 Irp->IoStatus.Information = sizeNeeded;
159 status = STATUS_BUFFER_TOO_SMALL;
160 break;
161 }
162
163 RtlZeroMemory(Irp->AssociatedIrp.SystemBuffer, sizeNeeded);
164
165 //
166 // ISSUE-2000/5/11-henrygab - need to update GET_MEDIA_TYPES_EX
167 //
168
169 mediaTypes->DeviceType = CdRomGetDeviceType(DeviceObject);
170
171 mediaTypes->MediaInfoCount = 1;
172 mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType = CD_ROM;
173 mediaInfo->DeviceSpecific.RemovableDiskInfo.NumberMediaSides = 1;
174 mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = MEDIA_READ_ONLY;
175 mediaInfo->DeviceSpecific.RemovableDiskInfo.Cylinders.QuadPart = fdoExtension->DiskGeometry.Cylinders.QuadPart;
176 mediaInfo->DeviceSpecific.RemovableDiskInfo.TracksPerCylinder = fdoExtension->DiskGeometry.TracksPerCylinder;
177 mediaInfo->DeviceSpecific.RemovableDiskInfo.SectorsPerTrack = fdoExtension->DiskGeometry.SectorsPerTrack;
178 mediaInfo->DeviceSpecific.RemovableDiskInfo.BytesPerSector = fdoExtension->DiskGeometry.BytesPerSector;
179
180 if (cdData->Mmc.IsMmc) {
181
182 //
183 // also report a removable disk
184 //
185 mediaTypes->MediaInfoCount += 1;
186
187 mediaInfo++;
188 mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType = RemovableMedia;
189 mediaInfo->DeviceSpecific.RemovableDiskInfo.NumberMediaSides = 1;
190 mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = MEDIA_READ_WRITE;
191 mediaInfo->DeviceSpecific.RemovableDiskInfo.Cylinders.QuadPart = fdoExtension->DiskGeometry.Cylinders.QuadPart;
192 mediaInfo->DeviceSpecific.RemovableDiskInfo.TracksPerCylinder = fdoExtension->DiskGeometry.TracksPerCylinder;
193 mediaInfo->DeviceSpecific.RemovableDiskInfo.SectorsPerTrack = fdoExtension->DiskGeometry.SectorsPerTrack;
194 mediaInfo->DeviceSpecific.RemovableDiskInfo.BytesPerSector = fdoExtension->DiskGeometry.BytesPerSector;
195 mediaInfo--;
196
197 }
198
199 //
200 // Status will either be success, if media is present, or no media.
201 // It would be optimal to base from density code and medium type, but not all devices
202 // have values for these fields.
203 //
204
205 //
206 // Send a TUR to determine if media is present.
207 //
208
209 srb.CdbLength = 6;
210 cdb = (PCDB)srb.Cdb;
211 cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
212
213 //
214 // Set timeout value.
215 //
216
217 srb.TimeOutValue = fdoExtension->TimeOutValue;
218
219 status = ClassSendSrbSynchronous(DeviceObject,
220 &srb,
221 NULL,
222 0,
223 FALSE);
224
225
226 TraceLog((CdromDebugWarning,
227 "CdRomDeviceControl: GET_MEDIA_TYPES status of TUR - %lx\n",
228 status));
229
230 if (NT_SUCCESS(status)) {
231
232 //
233 // set the disk's media as current if we can write to it.
234 //
235
236 if (cdData->Mmc.IsMmc && cdData->Mmc.WriteAllowed) {
237
238 mediaInfo++;
239 SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics,
240 MEDIA_CURRENTLY_MOUNTED);
241 mediaInfo--;
242
243
244 } else {
245
246 SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics,
247 MEDIA_CURRENTLY_MOUNTED);
248
249 }
250
251 }
252
253 Irp->IoStatus.Information = sizeNeeded;
254 status = STATUS_SUCCESS;
255 break;
256 }
257
258
259 case IOCTL_CDROM_RAW_READ: {
260
261 LARGE_INTEGER startingOffset;
262 ULONGLONG transferBytes;
263 ULONGLONG endOffset;
264 ULONGLONG mdlBytes;
265 //ULONG startingSector;
266 PRAW_READ_INFO rawReadInfo = (PRAW_READ_INFO)irpStack->Parameters.DeviceIoControl.Type3InputBuffer;
267
268 //
269 // Ensure that XA reads are supported.
270 //
271
272 if (TEST_FLAG(cdData->XAFlags, XA_NOT_SUPPORTED)) {
273 TraceLog((CdromDebugWarning,
274 "CdRomDeviceControl: XA Reads not supported. Flags (%x)\n",
275 cdData->XAFlags));
276 status = STATUS_INVALID_DEVICE_REQUEST;
277 break;
278 }
279
280 //
281 // Check that ending sector is on disc and buffers are there and of
282 // correct size.
283 //
284
285 if (rawReadInfo == NULL) {
286
287 //
288 // Called from user space. Save the userbuffer in the
289 // Type3InputBuffer so we can reduce the number of code paths.
290 //
291
292 irpStack->Parameters.DeviceIoControl.Type3InputBuffer =
293 Irp->AssociatedIrp.SystemBuffer;
294
295 //
296 // Called from user space. Validate the buffers.
297 //
298
299 rawReadInfo = (PRAW_READ_INFO)irpStack->Parameters.DeviceIoControl.Type3InputBuffer;
300
301 if (rawReadInfo == NULL) {
302
303 TraceLog((CdromDebugWarning,
304 "CdRomDeviceControl: Invalid I/O parameters for "
305 "XA Read (No extent info\n"));
306 status = STATUS_INVALID_PARAMETER;
307 break;
308
309 }
310
311 if (irpStack->Parameters.DeviceIoControl.InputBufferLength !=
312 sizeof(RAW_READ_INFO)) {
313
314 TraceLog((CdromDebugWarning,
315 "CdRomDeviceControl: Invalid I/O parameters for "
316 "XA Read (Invalid info buffer\n"));
317 status = STATUS_INVALID_PARAMETER;
318 break;
319
320 }
321 }
322
323 //
324 // if they don't request any data, just fail the request
325 //
326
327 if (rawReadInfo->SectorCount == 0) {
328
329 status = STATUS_INVALID_PARAMETER;
330 break;
331
332 }
333
334 startingOffset.QuadPart = rawReadInfo->DiskOffset.QuadPart;
335 /* startingSector = (ULONG)(rawReadInfo->DiskOffset.QuadPart >>
336 fdoExtension->SectorShift); */
337 transferBytes = (ULONGLONG)rawReadInfo->SectorCount * RAW_SECTOR_SIZE;
338
339 endOffset = (ULONGLONG)rawReadInfo->SectorCount * COOKED_SECTOR_SIZE;
340 endOffset += startingOffset.QuadPart;
341
342 //
343 // check for overflows....
344 //
345
346 if (transferBytes < (ULONGLONG)(rawReadInfo->SectorCount)) {
347 TraceLog((CdromDebugWarning,
348 "CdRomDeviceControl: Invalid I/O parameters for XA "
349 "Read (TransferBytes Overflow)\n"));
350 status = STATUS_INVALID_PARAMETER;
351 break;
352 }
353 if (endOffset < (ULONGLONG)startingOffset.QuadPart) {
354 TraceLog((CdromDebugWarning,
355 "CdRomDeviceControl: Invalid I/O parameters for XA "
356 "Read (EndingOffset Overflow)\n"));
357 status = STATUS_INVALID_PARAMETER;
358 break;
359 }
360 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
361 transferBytes) {
362 TraceLog((CdromDebugWarning,
363 "CdRomDeviceControl: Invalid I/O parameters for XA "
364 "Read (Bad buffer size)\n"));
365 status = STATUS_INVALID_PARAMETER;
366 break;
367 }
368 if (endOffset > (ULONGLONG)commonExtension->PartitionLength.QuadPart) {
369 TraceLog((CdromDebugWarning,
370 "CdRomDeviceControl: Invalid I/O parameters for XA "
371 "Read (Request Out of Bounds)\n"));
372 status = STATUS_INVALID_PARAMETER;
373 break;
374 }
375
376 //
377 // cannot validate the MdlAddress, since it is not included in any
378 // other location per the DDK and file system calls.
379 //
380
381 //
382 // validate the mdl describes at least the number of bytes
383 // requested from us.
384 //
385
386 mdlBytes = (ULONGLONG)MmGetMdlByteCount(Irp->MdlAddress);
387 if (mdlBytes < transferBytes) {
388 TraceLog((CdromDebugWarning,
389 "CdRomDeviceControl: Invalid MDL %s, Irp %p\n",
390 "size (5)", Irp));
391 status = STATUS_INVALID_PARAMETER;
392 break;
393 }
394
395 //
396 // HACKHACK - REF #0001
397 // The retry count will be in this irp's IRP_MN function,
398 // as the new irp was freed, and we therefore cannot use
399 // this irp's next stack location for this function.
400 // This may be a good location to store this info for
401 // when we remove RAW_READ (mode switching), as we will
402 // no longer have the nextIrpStackLocation to play with
403 // when that occurs
404 //
405 // once XA_READ is removed, then this hack can also be
406 // removed.
407 //
408 irpStack->MinorFunction = MAXIMUM_RETRIES; // HACKHACK - REF #0001
409
410 IoMarkIrpPending(Irp);
411 IoStartPacket(DeviceObject, Irp, NULL, NULL);
412
413 return STATUS_PENDING;
414 }
415
416 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX:
417 case IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX: {
418 TraceLog((CdromDebugTrace,
419 "CdRomDeviceControl: Get drive geometryEx\n"));
420 if ( irpStack->Parameters.DeviceIoControl.OutputBufferLength <
421 FIELD_OFFSET(DISK_GEOMETRY_EX, Data)) {
422 status = STATUS_BUFFER_TOO_SMALL;
423 Irp->IoStatus.Information = FIELD_OFFSET(DISK_GEOMETRY_EX, Data);
424 break;
425 }
426 IoMarkIrpPending(Irp);
427 IoStartPacket(DeviceObject, Irp, NULL, NULL);
428 return STATUS_PENDING;
429 }
430
431 case IOCTL_DISK_GET_DRIVE_GEOMETRY:
432 case IOCTL_CDROM_GET_DRIVE_GEOMETRY: {
433
434 TraceLog((CdromDebugTrace,
435 "CdRomDeviceControl: Get drive geometry\n"));
436
437 if ( irpStack->Parameters.DeviceIoControl.OutputBufferLength <
438 sizeof( DISK_GEOMETRY ) ) {
439
440 status = STATUS_BUFFER_TOO_SMALL;
441 Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
442 break;
443 }
444
445 IoMarkIrpPending(Irp);
446 IoStartPacket(DeviceObject, Irp, NULL, NULL);
447
448 return STATUS_PENDING;
449 }
450
451 case IOCTL_CDROM_READ_TOC_EX: {
452
453 PCDROM_READ_TOC_EX inputBuffer;
454
455 if (CdRomIsPlayActive(DeviceObject)) {
456 status = STATUS_DEVICE_BUSY;
457 break;
458 }
459
460 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
461 sizeof(CDROM_READ_TOC_EX)) {
462 status = STATUS_INFO_LENGTH_MISMATCH;
463 break;
464 }
465
466 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
467 MINIMUM_CDROM_READ_TOC_EX_SIZE) {
468 status = STATUS_BUFFER_TOO_SMALL;
469 Irp->IoStatus.Information = MINIMUM_CDROM_READ_TOC_EX_SIZE;
470 break;
471 }
472
473 if (irpStack->Parameters.Read.Length > ((USHORT)-1)) {
474 status = STATUS_INVALID_PARAMETER;
475 break;
476 }
477
478 inputBuffer = Irp->AssociatedIrp.SystemBuffer;
479
480 if ((inputBuffer->Reserved1 != 0) ||
481 (inputBuffer->Reserved2 != 0) ||
482 (inputBuffer->Reserved3 != 0)) {
483 status = STATUS_INVALID_PARAMETER;
484 break;
485 }
486
487 //
488 // NOTE: when adding new formats, ensure that first two bytes
489 // specify the amount of additional data available.
490 //
491
492 if ((inputBuffer->Format == CDROM_READ_TOC_EX_FORMAT_TOC ) ||
493 (inputBuffer->Format == CDROM_READ_TOC_EX_FORMAT_FULL_TOC) ||
494 (inputBuffer->Format == CDROM_READ_TOC_EX_FORMAT_CDTEXT )) {
495
496 // SessionTrack field is used
497
498 } else
499 if ((inputBuffer->Format == CDROM_READ_TOC_EX_FORMAT_SESSION) ||
500 (inputBuffer->Format == CDROM_READ_TOC_EX_FORMAT_PMA) ||
501 (inputBuffer->Format == CDROM_READ_TOC_EX_FORMAT_ATIP)) {
502
503 // SessionTrack field is reserved
504
505 if (inputBuffer->SessionTrack != 0) {
506 status = STATUS_INVALID_PARAMETER;
507 break;
508 }
509
510 } else {
511 status = STATUS_INVALID_PARAMETER;
512 break;
513 }
514
515 IoMarkIrpPending(Irp);
516 IoStartPacket(DeviceObject, Irp, NULL, NULL);
517 return STATUS_PENDING;
518 }
519
520 case IOCTL_CDROM_GET_LAST_SESSION: {
521
522 //
523 // If the cd is playing music then reject this request.
524 //
525
526 if (CdRomIsPlayActive(DeviceObject)) {
527 status = STATUS_DEVICE_BUSY;
528 break;
529 }
530
531 //
532 // Make sure the caller is requesting enough data to make this worth
533 // our while.
534 //
535
536 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
537 sizeof(CDROM_TOC_SESSION_DATA)) {
538
539 //
540 // they didn't request the entire TOC -- use _EX version
541 // for partial transfers and such.
542 //
543
544 status = STATUS_BUFFER_TOO_SMALL;
545 Irp->IoStatus.Information = sizeof(CDROM_TOC_SESSION_DATA);
546 break;
547 }
548
549 IoMarkIrpPending(Irp);
550 IoStartPacket(DeviceObject, Irp, NULL, NULL);
551
552 return STATUS_PENDING;
553 }
554
555 case IOCTL_CDROM_READ_TOC: {
556
557 //
558 // If the cd is playing music then reject this request.
559 //
560
561 if (CdRomIsPlayActive(DeviceObject)) {
562 status = STATUS_DEVICE_BUSY;
563 break;
564 }
565
566 //
567 // Make sure the caller is requesting enough data to make this worth
568 // our while.
569 //
570
571 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
572 sizeof(CDROM_TOC)) {
573
574 //
575 // they didn't request the entire TOC -- use _EX version
576 // for partial transfers and such.
577 //
578
579 status = STATUS_BUFFER_TOO_SMALL;
580 Irp->IoStatus.Information = sizeof(CDROM_TOC);
581 break;
582 }
583
584 IoMarkIrpPending(Irp);
585 IoStartPacket(DeviceObject, Irp, NULL, NULL);
586
587 return STATUS_PENDING;
588 }
589
590 case IOCTL_CDROM_PLAY_AUDIO_MSF: {
591
592 //
593 // Play Audio MSF
594 //
595
596 TraceLog((CdromDebugTrace,
597 "CdRomDeviceControl: Play audio MSF\n"));
598
599 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
600 sizeof(CDROM_PLAY_AUDIO_MSF)) {
601
602 //
603 // Indicate unsuccessful status.
604 //
605
606 status = STATUS_INFO_LENGTH_MISMATCH;
607 break;
608 }
609
610 IoMarkIrpPending(Irp);
611 IoStartPacket(DeviceObject, Irp, NULL, NULL);
612
613 return STATUS_PENDING;
614 }
615
616 case IOCTL_CDROM_SEEK_AUDIO_MSF: {
617
618
619 //
620 // Seek Audio MSF
621 //
622
623 TraceLog((CdromDebugTrace,
624 "CdRomDeviceControl: Seek audio MSF\n"));
625
626 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
627 sizeof(CDROM_SEEK_AUDIO_MSF)) {
628
629 //
630 // Indicate unsuccessful status.
631 //
632
633 status = STATUS_INFO_LENGTH_MISMATCH;
634 break;
635 }
636
637 IoMarkIrpPending(Irp);
638 IoStartPacket(DeviceObject, Irp, NULL, NULL);
639 return STATUS_PENDING;
640
641 }
642
643 case IOCTL_CDROM_PAUSE_AUDIO: {
644
645 //
646 // Pause audio
647 //
648
649 TraceLog((CdromDebugTrace,
650 "CdRomDeviceControl: Pause audio\n"));
651
652 IoMarkIrpPending(Irp);
653 IoStartPacket(DeviceObject, Irp, NULL, NULL);
654
655 return STATUS_PENDING;
656
657 break;
658 }
659
660 case IOCTL_CDROM_RESUME_AUDIO: {
661
662 //
663 // Resume audio
664 //
665
666 TraceLog((CdromDebugTrace,
667 "CdRomDeviceControl: Resume audio\n"));
668
669 IoMarkIrpPending(Irp);
670 IoStartPacket(DeviceObject, Irp, NULL, NULL);
671
672 return STATUS_PENDING;
673 }
674
675 case IOCTL_CDROM_READ_Q_CHANNEL: {
676
677 PCDROM_SUB_Q_DATA_FORMAT inputBuffer =
678 Irp->AssociatedIrp.SystemBuffer;
679
680 if(irpStack->Parameters.DeviceIoControl.InputBufferLength <
681 sizeof(CDROM_SUB_Q_DATA_FORMAT)) {
682
683 status = STATUS_INFO_LENGTH_MISMATCH;
684 break;
685 }
686
687 //
688 // check for all valid types of request
689 //
690
691 if (inputBuffer->Format != IOCTL_CDROM_CURRENT_POSITION &&
692 inputBuffer->Format != IOCTL_CDROM_MEDIA_CATALOG &&
693 inputBuffer->Format != IOCTL_CDROM_TRACK_ISRC ) {
694 status = STATUS_INVALID_PARAMETER;
695 Irp->IoStatus.Information = 0;
696 break;
697 }
698
699 IoMarkIrpPending(Irp);
700 IoStartPacket(DeviceObject, Irp, NULL, NULL);
701
702 return STATUS_PENDING;
703 }
704
705 case IOCTL_CDROM_GET_CONTROL: {
706
707 TraceLog((CdromDebugTrace,
708 "CdRomDeviceControl: Get audio control\n"));
709
710 //
711 // Verify user buffer is large enough for the data.
712 //
713
714 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
715 sizeof(CDROM_AUDIO_CONTROL)) {
716
717 //
718 // Indicate unsuccessful status and no data transferred.
719 //
720
721 status = STATUS_BUFFER_TOO_SMALL;
722 Irp->IoStatus.Information = sizeof(CDROM_AUDIO_CONTROL);
723 break;
724
725 }
726
727 IoMarkIrpPending(Irp);
728 IoStartPacket(DeviceObject, Irp, NULL, NULL);
729
730 return STATUS_PENDING;
731 }
732
733 case IOCTL_CDROM_GET_VOLUME: {
734
735 TraceLog((CdromDebugTrace,
736 "CdRomDeviceControl: Get volume control\n"));
737
738 //
739 // Verify user buffer is large enough for data.
740 //
741
742 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
743 sizeof(VOLUME_CONTROL)) {
744
745 //
746 // Indicate unsuccessful status and no data transferred.
747 //
748
749 status = STATUS_BUFFER_TOO_SMALL;
750 Irp->IoStatus.Information = sizeof(VOLUME_CONTROL);
751 break;
752
753 }
754
755 IoMarkIrpPending(Irp);
756 IoStartPacket(DeviceObject, Irp, NULL, NULL);
757
758 return STATUS_PENDING;
759 }
760
761 case IOCTL_CDROM_SET_VOLUME: {
762
763 TraceLog((CdromDebugTrace,
764 "CdRomDeviceControl: Set volume control\n"));
765
766 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
767 sizeof(VOLUME_CONTROL)) {
768
769 //
770 // Indicate unsuccessful status.
771 //
772
773 status = STATUS_INFO_LENGTH_MISMATCH;
774 break;
775
776 }
777
778 IoMarkIrpPending(Irp);
779 IoStartPacket(DeviceObject, Irp, NULL, NULL);
780
781 return STATUS_PENDING;
782 }
783
784 case IOCTL_CDROM_STOP_AUDIO: {
785
786 //
787 // Stop play.
788 //
789
790 TraceLog((CdromDebugTrace,
791 "CdRomDeviceControl: Stop audio\n"));
792
793 IoMarkIrpPending(Irp);
794 IoStartPacket(DeviceObject, Irp, NULL, NULL);
795
796 return STATUS_PENDING;
797 }
798
799 case IOCTL_STORAGE_CHECK_VERIFY:
800 case IOCTL_DISK_CHECK_VERIFY:
801 case IOCTL_CDROM_CHECK_VERIFY: {
802
803 TraceLog((CdromDebugTrace,
804 "CdRomDeviceControl: [%p] Check Verify\n", Irp));
805
806 if((irpStack->Parameters.DeviceIoControl.OutputBufferLength) &&
807 (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG))) {
808
809 TraceLog((CdromDebugWarning,
810 "CdRomDeviceControl: Check Verify: media count "
811 "buffer too small\n"));
812
813 status = STATUS_BUFFER_TOO_SMALL;
814 Irp->IoStatus.Information = sizeof(ULONG);
815 break;
816 }
817
818 IoMarkIrpPending(Irp);
819 IoStartPacket(DeviceObject, Irp, NULL, NULL);
820
821 return STATUS_PENDING;
822 }
823
824 case IOCTL_DVD_READ_STRUCTURE: {
825
826 TraceLog((CdromDebugTrace,
827 "DvdDeviceControl: [%p] IOCTL_DVD_READ_STRUCTURE\n", Irp));
828
829 if (cdData->DvdRpc0Device && cdData->DvdRpc0LicenseFailure) {
830 TraceLog((CdromDebugWarning,
831 "DvdDeviceControl: License Failure\n"));
832 status = STATUS_COPY_PROTECTION_FAILURE;
833 break;
834 }
835
836 if (cdData->DvdRpc0Device && cdData->Rpc0RetryRegistryCallback) {
837 //
838 // if currently in-progress, this will just return.
839 // prevents looping by doing that interlockedExchange()
840 //
841 TraceLog((CdromDebugWarning,
842 "DvdDeviceControl: PickRegion() from "
843 "READ_STRUCTURE\n"));
844 CdRomPickDvdRegion(DeviceObject);
845 }
846
847
848 if(irpStack->Parameters.DeviceIoControl.InputBufferLength <
849 sizeof(DVD_READ_STRUCTURE)) {
850
851 TraceLog((CdromDebugWarning,
852 "DvdDeviceControl - READ_STRUCTURE: input buffer "
853 "length too small (was %d should be %d)\n",
854 irpStack->Parameters.DeviceIoControl.InputBufferLength,
855 sizeof(DVD_READ_STRUCTURE)));
856 status = STATUS_INVALID_PARAMETER;
857 break;
858 }
859
860 if(irpStack->Parameters.DeviceIoControl.OutputBufferLength <
861 sizeof(READ_DVD_STRUCTURES_HEADER)) {
862
863 TraceLog((CdromDebugWarning,
864 "DvdDeviceControl - READ_STRUCTURE: output buffer "
865 "cannot hold header information\n"));
866 status = STATUS_BUFFER_TOO_SMALL;
867 Irp->IoStatus.Information = sizeof(READ_DVD_STRUCTURES_HEADER);
868 break;
869 }
870
871 if(irpStack->Parameters.DeviceIoControl.OutputBufferLength >
872 MAXUSHORT) {
873
874 //
875 // key length must fit in two bytes
876 //
877 TraceLog((CdromDebugWarning,
878 "DvdDeviceControl - READ_STRUCTURE: output buffer "
879 "too large\n"));
880 status = STATUS_INVALID_PARAMETER;
881 break;
882 }
883
884 IoMarkIrpPending(Irp);
885 IoStartPacket(DeviceObject, Irp, NULL, NULL);
886
887 return STATUS_PENDING;
888 }
889
890 case IOCTL_DVD_START_SESSION: {
891
892 TraceLog((CdromDebugTrace,
893 "DvdDeviceControl: [%p] IOCTL_DVD_START_SESSION\n", Irp));
894
895 if (cdData->DvdRpc0Device && cdData->DvdRpc0LicenseFailure) {
896 TraceLog((CdromDebugWarning,
897 "DvdDeviceControl: License Failure\n"));
898 status = STATUS_COPY_PROTECTION_FAILURE;
899 break;
900 }
901
902 if(irpStack->Parameters.DeviceIoControl.OutputBufferLength <
903 sizeof(DVD_SESSION_ID)) {
904
905 TraceLog((CdromDebugWarning,
906 "DvdDeviceControl: DVD_START_SESSION - output "
907 "buffer too small\n"));
908 status = STATUS_BUFFER_TOO_SMALL;
909 Irp->IoStatus.Information = sizeof(DVD_SESSION_ID);
910 break;
911 }
912
913 IoMarkIrpPending(Irp);
914 IoStartPacket(DeviceObject, Irp, NULL, NULL);
915
916 return STATUS_PENDING;
917 }
918
919 case IOCTL_DVD_SEND_KEY:
920 case IOCTL_DVD_SEND_KEY2: {
921
922 PDVD_COPY_PROTECT_KEY key = Irp->AssociatedIrp.SystemBuffer;
923 //ULONG keyLength;
924
925 TraceLog((CdromDebugTrace,
926 "DvdDeviceControl: [%p] IOCTL_DVD_SEND_KEY\n", Irp));
927
928 if (cdData->DvdRpc0Device && cdData->DvdRpc0LicenseFailure) {
929 TraceLog((CdromDebugWarning,
930 "DvdDeviceControl: License Failure\n"));
931 status = STATUS_COPY_PROTECTION_FAILURE;
932 break;
933 }
934
935 if((irpStack->Parameters.DeviceIoControl.InputBufferLength <
936 sizeof(DVD_COPY_PROTECT_KEY)) ||
937 (irpStack->Parameters.DeviceIoControl.InputBufferLength !=
938 key->KeyLength)) {
939
940 //
941 // Key is too small to have a header or the key length doesn't
942 // match the input buffer length. Key must be invalid
943 //
944
945 TraceLog((CdromDebugWarning,
946 "DvdDeviceControl: [%p] IOCTL_DVD_SEND_KEY - "
947 "key is too small or does not match KeyLength\n",
948 Irp));
949 status = STATUS_INVALID_PARAMETER;
950 break;
951 }
952
953 //
954 // allow only certain key type (non-destructive) to go through
955 // IOCTL_DVD_SEND_KEY (which only requires READ access to the device
956 //
957 if (ioctlCode == IOCTL_DVD_SEND_KEY) {
958
959 if ((key->KeyType != DvdChallengeKey) &&
960 (key->KeyType != DvdBusKey2) &&
961 (key->KeyType != DvdInvalidateAGID)) {
962
963 status = STATUS_INVALID_PARAMETER;
964 break;
965 }
966 }
967
968 if (cdData->DvdRpc0Device) {
969
970 if (key->KeyType == DvdSetRpcKey) {
971
972 PDVD_SET_RPC_KEY rpcKey = (PDVD_SET_RPC_KEY) key->KeyData;
973
974 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
975 DVD_SET_RPC_KEY_LENGTH) {
976
977 status = STATUS_INVALID_PARAMETER;
978 break;
979 }
980
981 //
982 // we have a request to set region code
983 // on a RPC0 device which doesn't support
984 // region coding.
985 //
986 // we have to fake it.
987 //
988
989 KeWaitForMutexObject(
990 &cdData->Rpc0RegionMutex,
991 UserRequest,
992 KernelMode,
993 FALSE,
994 NULL
995 );
996
997 if (cdData->DvdRpc0Device && cdData->Rpc0RetryRegistryCallback) {
998 //
999 // if currently in-progress, this will just return.
1000 // prevents looping by doing that interlockedExchange()
1001 //
1002 TraceLog((CdromDebugWarning,
1003 "DvdDeviceControl: PickRegion() from "
1004 "SEND_KEY\n"));
1005 CdRomPickDvdRegion(DeviceObject);
1006 }
1007
1008 if (cdData->Rpc0SystemRegion == rpcKey->PreferredDriveRegionCode) {
1009
1010 //
1011 // nothing to change
1012 //
1013 TraceLog((CdromDebugWarning,
1014 "DvdDeviceControl (%p) => not changing "
1015 "regions -- requesting current region\n",
1016 DeviceObject));
1017 status = STATUS_SUCCESS;
1018
1019 } else if (cdData->Rpc0SystemRegionResetCount == 0) {
1020
1021 //
1022 // not allowed to change it again
1023 //
1024
1025 TraceLog((CdromDebugWarning,
1026 "DvdDeviceControl (%p) => no more region "
1027 "changes are allowed for this device\n",
1028 DeviceObject));
1029 status = STATUS_CSS_RESETS_EXHAUSTED;
1030
1031 } else {
1032
1033 //ULONG i;
1034 UCHAR mask;
1035 ULONG bufferLen;
1036 PDVD_READ_STRUCTURE dvdReadStructure;
1037 PDVD_COPYRIGHT_DESCRIPTOR dvdCopyRight;
1038 IO_STATUS_BLOCK ioStatus;
1039 UCHAR mediaRegionData;
1040
1041 mask = ~rpcKey->PreferredDriveRegionCode;
1042
1043 if (CountOfSetBitsUChar(mask) != 1) {
1044
1045 status = STATUS_INVALID_DEVICE_REQUEST;
1046 break;
1047 }
1048
1049 //
1050 // this test will always be TRUE except during initial
1051 // automatic selection of the first region.
1052 //
1053
1054 if (cdData->Rpc0SystemRegion != 0xff) {
1055
1056 //
1057 // make sure we have a media in the drive with the same
1058 // region code if the drive is already has a region set
1059 //
1060
1061 TraceLog((CdromDebugTrace,
1062 "DvdDeviceControl (%p) => Checking "
1063 "media region\n",
1064 DeviceObject));
1065
1066 bufferLen = max(sizeof(DVD_DESCRIPTOR_HEADER) +
1067 sizeof(DVD_COPYRIGHT_DESCRIPTOR),
1068 sizeof(DVD_READ_STRUCTURE)
1069 );
1070
1071 dvdReadStructure = (PDVD_READ_STRUCTURE)
1072 ExAllocatePoolWithTag(PagedPool,
1073 bufferLen,
1074 DVD_TAG_RPC2_CHECK);
1075
1076 if (dvdReadStructure == NULL) {
1077 status = STATUS_INSUFFICIENT_RESOURCES;
1078 KeReleaseMutex(&cdData->Rpc0RegionMutex,FALSE);
1079 break;
1080 }
1081
1082 dvdCopyRight = (PDVD_COPYRIGHT_DESCRIPTOR)
1083 ((PDVD_DESCRIPTOR_HEADER) dvdReadStructure)->Data;
1084
1085 //
1086 // check to see if we have a DVD device
1087 //
1088
1089 RtlZeroMemory (dvdReadStructure, bufferLen);
1090 dvdReadStructure->Format = DvdCopyrightDescriptor;
1091
1092 //
1093 // Build a request for READ_KEY
1094 //
1095 ClassSendDeviceIoControlSynchronous(
1096 IOCTL_DVD_READ_STRUCTURE,
1097 DeviceObject,
1098 dvdReadStructure,
1099 sizeof(DVD_READ_STRUCTURE),
1100 sizeof(DVD_DESCRIPTOR_HEADER) +
1101 sizeof(DVD_COPYRIGHT_DESCRIPTOR),
1102 FALSE,
1103 &ioStatus);
1104
1105 //
1106 // this is just to prevent bugs from creeping in
1107 // if status is not set later in development
1108 //
1109
1110 status = ioStatus.Status;
1111
1112 //
1113 // handle errors
1114 //
1115
1116 if (!NT_SUCCESS(status)) {
1117 KeReleaseMutex(&cdData->Rpc0RegionMutex,FALSE);
1118 ExFreePool(dvdReadStructure);
1119 status = STATUS_INVALID_DEVICE_REQUEST;
1120 break;
1121 }
1122
1123 //
1124 // save the mediaRegionData before freeing the
1125 // allocated memory
1126 //
1127
1128 mediaRegionData =
1129 dvdCopyRight->RegionManagementInformation;
1130 ExFreePool(dvdReadStructure);
1131
1132 TraceLog((CdromDebugWarning,
1133 "DvdDeviceControl (%p) => new mask is %x"
1134 " MediaRegionData is %x\n", DeviceObject,
1135 rpcKey->PreferredDriveRegionCode,
1136 mediaRegionData));
1137
1138 //
1139 // the media region must match the requested region
1140 // for RPC0 drives for initial region selection
1141 //
1142
1143 if (((UCHAR)~(mediaRegionData | rpcKey->PreferredDriveRegionCode)) == 0) {
1144 KeReleaseMutex(&cdData->Rpc0RegionMutex,FALSE);
1145 status = STATUS_CSS_REGION_MISMATCH;
1146 break;
1147 }
1148
1149 }
1150
1151 //
1152 // now try to set the region
1153 //
1154
1155 TraceLog((CdromDebugTrace,
1156 "DvdDeviceControl (%p) => Soft-Setting "
1157 "region of RPC1 device to %x\n",
1158 DeviceObject,
1159 rpcKey->PreferredDriveRegionCode
1160 ));
1161
1162 status = CdRomSetRpc0Settings(DeviceObject,
1163 rpcKey->PreferredDriveRegionCode);
1164
1165 if (!NT_SUCCESS(status)) {
1166 TraceLog((CdromDebugWarning,
1167 "DvdDeviceControl (%p) => Could not "
1168 "set region code (%x)\n",
1169 DeviceObject, status
1170 ));
1171 } else {
1172
1173 TraceLog((CdromDebugTrace,
1174 "DvdDeviceControl (%p) => New region set "
1175 " for RPC1 drive\n", DeviceObject));
1176
1177 //
1178 // if it worked, our extension is already updated.
1179 // release the mutex
1180 //
1181
1182 DebugPrint ((4, "DvdDeviceControl (%p) => DVD current "
1183 "region bitmap 0x%x\n", DeviceObject,
1184 cdData->Rpc0SystemRegion));
1185 DebugPrint ((4, "DvdDeviceControl (%p) => DVD region "
1186 " reset Count 0x%x\n", DeviceObject,
1187 cdData->Rpc0SystemRegionResetCount));
1188 }
1189
1190 }
1191
1192 KeReleaseMutex(&cdData->Rpc0RegionMutex,FALSE);
1193 break;
1194 } // end of key->KeyType == DvdSetRpcKey
1195 } // end of Rpc0Device hacks
1196
1197 IoMarkIrpPending(Irp);
1198 IoStartPacket(DeviceObject, Irp, NULL, NULL);
1199 return STATUS_PENDING;
1200 }
1201
1202 case IOCTL_DVD_READ_KEY: {
1203
1204 PDVD_COPY_PROTECT_KEY keyParameters = Irp->AssociatedIrp.SystemBuffer;
1205 ULONG keyLength;
1206
1207 TraceLog((CdromDebugTrace,
1208 "DvdDeviceControl: [%p] IOCTL_DVD_READ_KEY\n", Irp));
1209
1210 if (cdData->DvdRpc0Device && cdData->DvdRpc0LicenseFailure) {
1211 TraceLog((CdromDebugWarning,
1212 "DvdDeviceControl: License Failure\n"));
1213 status = STATUS_COPY_PROTECTION_FAILURE;
1214 break;
1215 }
1216
1217 if (cdData->DvdRpc0Device && cdData->Rpc0RetryRegistryCallback) {
1218 TraceLog((CdromDebugWarning,
1219 "DvdDeviceControl: PickRegion() from READ_KEY\n"));
1220 CdRomPickDvdRegion(DeviceObject);
1221 }
1222
1223
1224 if(irpStack->Parameters.DeviceIoControl.InputBufferLength <
1225 sizeof(DVD_COPY_PROTECT_KEY)) {
1226
1227 TraceLog((CdromDebugWarning,
1228 "DvdDeviceControl: EstablishDriveKey - challenge "
1229 "key buffer too small\n"));
1230
1231 status = STATUS_INVALID_PARAMETER;
1232 break;
1233
1234 }
1235
1236
1237 switch(keyParameters->KeyType) {
1238
1239 case DvdChallengeKey:
1240 keyLength = DVD_CHALLENGE_KEY_LENGTH;
1241 break;
1242
1243 case DvdBusKey1:
1244 case DvdBusKey2:
1245
1246 keyLength = DVD_BUS_KEY_LENGTH;
1247 break;
1248
1249 case DvdTitleKey:
1250 keyLength = DVD_TITLE_KEY_LENGTH;
1251 break;
1252
1253 case DvdAsf:
1254 keyLength = DVD_ASF_LENGTH;
1255 break;
1256
1257 case DvdDiskKey:
1258 keyLength = DVD_DISK_KEY_LENGTH;
1259 break;
1260
1261 case DvdGetRpcKey:
1262 keyLength = DVD_RPC_KEY_LENGTH;
1263 break;
1264
1265 default:
1266 keyLength = sizeof(DVD_COPY_PROTECT_KEY);
1267 break;
1268 }
1269
1270 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1271 keyLength) {
1272
1273 TraceLog((CdromDebugWarning,
1274 "DvdDeviceControl: EstablishDriveKey - output "
1275 "buffer too small\n"));
1276 status = STATUS_BUFFER_TOO_SMALL;
1277 Irp->IoStatus.Information = keyLength;
1278 break;
1279 }
1280
1281 if (keyParameters->KeyType == DvdGetRpcKey) {
1282
1283 CdRomPickDvdRegion(DeviceObject);
1284 }
1285
1286 if ((keyParameters->KeyType == DvdGetRpcKey) &&
1287 (cdData->DvdRpc0Device)) {
1288
1289 PDVD_RPC_KEY rpcKey;
1290 rpcKey = (PDVD_RPC_KEY)keyParameters->KeyData;
1291 RtlZeroMemory (rpcKey, sizeof (*rpcKey));
1292
1293 KeWaitForMutexObject(
1294 &cdData->Rpc0RegionMutex,
1295 UserRequest,
1296 KernelMode,
1297 FALSE,
1298 NULL
1299 );
1300
1301 //
1302 // make up the data
1303 //
1304 rpcKey->UserResetsAvailable = cdData->Rpc0SystemRegionResetCount;
1305 rpcKey->ManufacturerResetsAvailable = 0;
1306 if (cdData->Rpc0SystemRegion == 0xff) {
1307 rpcKey->TypeCode = 0;
1308 } else {
1309 rpcKey->TypeCode = 1;
1310 }
1311 rpcKey->RegionMask = (UCHAR) cdData->Rpc0SystemRegion;
1312 rpcKey->RpcScheme = 1;
1313
1314 KeReleaseMutex(
1315 &cdData->Rpc0RegionMutex,
1316 FALSE
1317 );
1318
1319 Irp->IoStatus.Information = DVD_RPC_KEY_LENGTH;
1320 status = STATUS_SUCCESS;
1321 break;
1322
1323 } else if (keyParameters->KeyType == DvdDiskKey) {
1324
1325 PDVD_COPY_PROTECT_KEY keyHeader;
1326 PDVD_READ_STRUCTURE readStructureRequest;
1327
1328 //
1329 // Special case - build a request to get the dvd structure
1330 // so we can get the disk key.
1331 //
1332
1333 //
1334 // save the key header so we can restore the interesting
1335 // parts later
1336 //
1337
1338 keyHeader = ExAllocatePoolWithTag(NonPagedPool,
1339 sizeof(DVD_COPY_PROTECT_KEY),
1340 DVD_TAG_READ_KEY);
1341
1342 if(keyHeader == NULL) {
1343
1344 //
1345 // Can't save the context so return an error
1346 //
1347
1348 TraceLog((CdromDebugWarning,
1349 "DvdDeviceControl - READ_KEY: unable to "
1350 "allocate context\n"));
1351 status = STATUS_INSUFFICIENT_RESOURCES;
1352 break;
1353 }
1354
1355 RtlCopyMemory(keyHeader,
1356 Irp->AssociatedIrp.SystemBuffer,
1357 sizeof(DVD_COPY_PROTECT_KEY));
1358
1359 IoCopyCurrentIrpStackLocationToNext(Irp);
1360
1361 nextStack = IoGetNextIrpStackLocation(Irp);
1362
1363 nextStack->Parameters.DeviceIoControl.IoControlCode =
1364 IOCTL_DVD_READ_STRUCTURE;
1365
1366 readStructureRequest = Irp->AssociatedIrp.SystemBuffer;
1367 readStructureRequest->Format = DvdDiskKeyDescriptor;
1368 readStructureRequest->BlockByteOffset.QuadPart = 0;
1369 readStructureRequest->LayerNumber = 0;
1370 readStructureRequest->SessionId = keyHeader->SessionId;
1371
1372 nextStack->Parameters.DeviceIoControl.InputBufferLength =
1373 sizeof(DVD_READ_STRUCTURE);
1374
1375 nextStack->Parameters.DeviceIoControl.OutputBufferLength =
1376 sizeof(READ_DVD_STRUCTURES_HEADER) + sizeof(DVD_DISK_KEY_DESCRIPTOR);
1377
1378 IoSetCompletionRoutine(Irp,
1379 CdRomDvdReadDiskKeyCompletion,
1380 (PVOID) keyHeader,
1381 TRUE,
1382 TRUE,
1383 TRUE);
1384
1385 {
1386 UCHAR uniqueAddress;
1387 ClassAcquireRemoveLock(DeviceObject, (PIRP)&uniqueAddress);
1388 ClassReleaseRemoveLock(DeviceObject, Irp);
1389
1390 IoMarkIrpPending(Irp);
1391 IoCallDriver(commonExtension->DeviceObject, Irp);
1392 status = STATUS_PENDING;
1393
1394 ClassReleaseRemoveLock(DeviceObject, (PIRP)&uniqueAddress);
1395 }
1396
1397 return STATUS_PENDING;
1398
1399 } else {
1400
1401 IoMarkIrpPending(Irp);
1402 IoStartPacket(DeviceObject, Irp, NULL, NULL);
1403
1404 }
1405 return STATUS_PENDING;
1406 }
1407
1408 case IOCTL_DVD_END_SESSION: {
1409
1410 PDVD_SESSION_ID sessionId = Irp->AssociatedIrp.SystemBuffer;
1411
1412 TraceLog((CdromDebugTrace,
1413 "DvdDeviceControl: [%p] END_SESSION\n", Irp));
1414
1415 if (cdData->DvdRpc0Device && cdData->DvdRpc0LicenseFailure) {
1416 TraceLog((CdromDebugWarning,
1417 "DvdDeviceControl: License Failure\n"));
1418 status = STATUS_COPY_PROTECTION_FAILURE;
1419 break;
1420 }
1421
1422 if(irpStack->Parameters.DeviceIoControl.InputBufferLength <
1423 sizeof(DVD_SESSION_ID)) {
1424
1425 TraceLog((CdromDebugWarning,
1426 "DvdDeviceControl: EndSession - input buffer too "
1427 "small\n"));
1428 status = STATUS_INVALID_PARAMETER;
1429 break;
1430 }
1431
1432 IoMarkIrpPending(Irp);
1433
1434 if(*sessionId == DVD_END_ALL_SESSIONS) {
1435
1436 status = CdRomDvdEndAllSessionsCompletion(DeviceObject, Irp, NULL);
1437
1438 if(status == STATUS_SUCCESS) {
1439
1440 //
1441 // Just complete the request - it was never issued to the
1442 // lower device
1443 //
1444
1445 break;
1446
1447 } else {
1448
1449 return STATUS_PENDING;
1450
1451 }
1452 }
1453
1454 IoStartPacket(DeviceObject, Irp, NULL, NULL);
1455
1456 return STATUS_PENDING;
1457 }
1458
1459 case IOCTL_DVD_GET_REGION: {
1460
1461 PDVD_COPY_PROTECT_KEY copyProtectKey;
1462 ULONG keyLength;
1463 IO_STATUS_BLOCK ioStatus;
1464 PDVD_DESCRIPTOR_HEADER dvdHeader;
1465 PDVD_COPYRIGHT_DESCRIPTOR copyRightDescriptor;
1466 PDVD_REGION dvdRegion;
1467 PDVD_READ_STRUCTURE readStructure;
1468 PDVD_RPC_KEY rpcKey;
1469
1470 TraceLog((CdromDebugTrace,
1471 "DvdDeviceControl: [%p] IOCTL_DVD_GET_REGION\n", Irp));
1472
1473 if (cdData->DvdRpc0Device && cdData->DvdRpc0LicenseFailure) {
1474 TraceLog((CdromDebugWarning,
1475 "DvdDeviceControl: License Failure\n"));
1476 status = STATUS_COPY_PROTECTION_FAILURE;
1477 break;
1478 }
1479
1480 if(irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1481 sizeof(DVD_REGION)) {
1482
1483 TraceLog((CdromDebugWarning,
1484 "DvdDeviceControl: output buffer DVD_REGION too small\n"));
1485 status = STATUS_INVALID_PARAMETER;
1486 break;
1487 }
1488
1489 //
1490 // figure out how much data buffer we need
1491 //
1492
1493 keyLength = max(sizeof(DVD_DESCRIPTOR_HEADER) +
1494 sizeof(DVD_COPYRIGHT_DESCRIPTOR),
1495 sizeof(DVD_READ_STRUCTURE)
1496 );
1497 keyLength = max(keyLength,
1498 DVD_RPC_KEY_LENGTH
1499 );
1500
1501 //
1502 // round the size to nearest ULONGLONG -- why?
1503 //
1504
1505 keyLength += sizeof(ULONGLONG) - (keyLength & (sizeof(ULONGLONG) - 1));
1506
1507 readStructure = ExAllocatePoolWithTag(NonPagedPool,
1508 keyLength,
1509 DVD_TAG_READ_KEY);
1510 if (readStructure == NULL) {
1511 status = STATUS_INSUFFICIENT_RESOURCES;
1512 break;
1513 }
1514
1515 RtlZeroMemory (readStructure, keyLength);
1516 readStructure->Format = DvdCopyrightDescriptor;
1517
1518 //
1519 // Build a request for READ_STRUCTURE
1520 //
1521
1522 ClassSendDeviceIoControlSynchronous(
1523 IOCTL_DVD_READ_STRUCTURE,
1524 DeviceObject,
1525 readStructure,
1526 keyLength,
1527 sizeof(DVD_DESCRIPTOR_HEADER) +
1528 sizeof(DVD_COPYRIGHT_DESCRIPTOR),
1529 FALSE,
1530 &ioStatus);
1531
1532 status = ioStatus.Status;
1533
1534 if (!NT_SUCCESS(status)) {
1535 TraceLog((CdromDebugWarning,
1536 "CdRomDvdGetRegion => read structure failed %x\n",
1537 status));
1538 ExFreePool(readStructure);
1539 break;
1540 }
1541
1542 //
1543 // we got the copyright descriptor, so now get the region if possible
1544 //
1545
1546 dvdHeader = (PDVD_DESCRIPTOR_HEADER) readStructure;
1547 copyRightDescriptor = (PDVD_COPYRIGHT_DESCRIPTOR) dvdHeader->Data;
1548
1549 //
1550 // the original irp's systembuffer has a copy of the info that
1551 // should be passed down in the request
1552 //
1553
1554 dvdRegion = Irp->AssociatedIrp.SystemBuffer;
1555
1556 dvdRegion->CopySystem = copyRightDescriptor->CopyrightProtectionType;
1557 dvdRegion->RegionData = copyRightDescriptor->RegionManagementInformation;
1558
1559 //
1560 // now reuse the buffer to request the copy protection info
1561 //
1562
1563 copyProtectKey = (PDVD_COPY_PROTECT_KEY) readStructure;
1564 RtlZeroMemory (copyProtectKey, DVD_RPC_KEY_LENGTH);
1565 copyProtectKey->KeyLength = DVD_RPC_KEY_LENGTH;
1566 copyProtectKey->KeyType = DvdGetRpcKey;
1567
1568 //
1569 // send a request for READ_KEY
1570 //
1571
1572 ClassSendDeviceIoControlSynchronous(
1573 IOCTL_DVD_READ_KEY,
1574 DeviceObject,
1575 copyProtectKey,
1576 DVD_RPC_KEY_LENGTH,
1577 DVD_RPC_KEY_LENGTH,
1578 FALSE,
1579 &ioStatus);
1580 status = ioStatus.Status;
1581
1582 if (!NT_SUCCESS(status)) {
1583 TraceLog((CdromDebugWarning,
1584 "CdRomDvdGetRegion => read key failed %x\n",
1585 status));
1586 ExFreePool(readStructure);
1587 break;
1588 }
1589
1590 //
1591 // the request succeeded. if a supported scheme is returned,
1592 // then return the information to the caller
1593 //
1594
1595 rpcKey = (PDVD_RPC_KEY) copyProtectKey->KeyData;
1596
1597 if (rpcKey->RpcScheme == 1) {
1598
1599 if (rpcKey->TypeCode) {
1600
1601 dvdRegion->SystemRegion = ~rpcKey->RegionMask;
1602 dvdRegion->ResetCount = rpcKey->UserResetsAvailable;
1603
1604 } else {
1605
1606 //
1607 // the drive has not been set for any region
1608 //
1609
1610 dvdRegion->SystemRegion = 0;
1611 dvdRegion->ResetCount = rpcKey->UserResetsAvailable;
1612 }
1613 Irp->IoStatus.Information = sizeof(DVD_REGION);
1614
1615 } else {
1616
1617 TraceLog((CdromDebugWarning,
1618 "CdRomDvdGetRegion => rpcKey->RpcScheme != 1\n"));
1619 status = STATUS_INVALID_DEVICE_REQUEST;
1620 }
1621
1622 ExFreePool(readStructure);
1623 break;
1624 }
1625
1626
1627 case IOCTL_STORAGE_SET_READ_AHEAD: {
1628
1629 if(irpStack->Parameters.DeviceIoControl.InputBufferLength <
1630 sizeof(STORAGE_SET_READ_AHEAD)) {
1631
1632 TraceLog((CdromDebugWarning,
1633 "DvdDeviceControl: SetReadAhead buffer too small\n"));
1634 status = STATUS_INVALID_PARAMETER;
1635 break;
1636 }
1637
1638 IoMarkIrpPending(Irp);
1639 IoStartPacket(DeviceObject, Irp, NULL, NULL);
1640
1641 return STATUS_PENDING;
1642 }
1643
1644 case IOCTL_DISK_IS_WRITABLE: {
1645
1646 IoMarkIrpPending(Irp);
1647 IoStartPacket(DeviceObject, Irp, NULL, NULL);
1648
1649 return STATUS_PENDING;
1650
1651 }
1652
1653 case IOCTL_DISK_GET_DRIVE_LAYOUT: {
1654
1655 ULONG size;
1656
1657 //
1658 // we always fake zero or one partitions, and one partition
1659 // structure is included in DRIVE_LAYOUT_INFORMATION
1660 //
1661
1662 size = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION, PartitionEntry[1]);
1663
1664
1665 TraceLog((CdromDebugTrace,
1666 "CdRomDeviceControl: Get drive layout\n"));
1667 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < size) {
1668 status = STATUS_BUFFER_TOO_SMALL;
1669 Irp->IoStatus.Information = size;
1670 break;
1671 }
1672
1673 IoMarkIrpPending(Irp);
1674 IoStartPacket(DeviceObject, Irp, NULL, NULL);
1675 return STATUS_PENDING;
1676
1677
1678 }
1679 case IOCTL_DISK_GET_DRIVE_LAYOUT_EX: {
1680
1681 ULONG size;
1682
1683 //
1684 // we always fake zero or one partitions, and one partition
1685 // structure is included in DRIVE_LAYOUT_INFORMATION_EX
1686 //
1687
1688 size = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[1]);
1689
1690 TraceLog((CdromDebugTrace,
1691 "CdRomDeviceControl: Get drive layout ex\n"));
1692 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < size) {
1693 status = STATUS_BUFFER_TOO_SMALL;
1694 Irp->IoStatus.Information = size;
1695 break;
1696 }
1697
1698 IoMarkIrpPending(Irp);
1699 IoStartPacket(DeviceObject, Irp, NULL, NULL);
1700 return STATUS_PENDING;
1701
1702 }
1703
1704
1705 case IOCTL_DISK_GET_PARTITION_INFO: {
1706
1707 //
1708 // Check that the buffer is large enough.
1709 //
1710
1711 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1712 sizeof(PARTITION_INFORMATION)) {
1713
1714 status = STATUS_BUFFER_TOO_SMALL;
1715 Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);
1716 break;
1717 }
1718
1719 IoMarkIrpPending(Irp);
1720 IoStartPacket(DeviceObject, Irp, NULL, NULL);
1721 return STATUS_PENDING;
1722
1723 }
1724 case IOCTL_DISK_GET_PARTITION_INFO_EX: {
1725
1726 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1727 sizeof(PARTITION_INFORMATION_EX)) {
1728
1729 status = STATUS_BUFFER_TOO_SMALL;
1730 Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION_EX);
1731 break;
1732 }
1733
1734 IoMarkIrpPending(Irp);
1735 IoStartPacket(DeviceObject, Irp, NULL, NULL);
1736 return STATUS_PENDING;
1737 }
1738
1739 case IOCTL_DISK_VERIFY: {
1740
1741 TraceLog((CdromDebugTrace,
1742 "IOCTL_DISK_VERIFY to device %p through irp %p\n",
1743 DeviceObject, Irp));
1744
1745 //
1746 // Validate buffer length.
1747 //
1748
1749 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
1750 sizeof(VERIFY_INFORMATION)) {
1751
1752 status = STATUS_INFO_LENGTH_MISMATCH;
1753 break;
1754 }
1755 IoMarkIrpPending(Irp);
1756 IoStartPacket(DeviceObject, Irp, NULL, NULL);
1757 return STATUS_PENDING;
1758 }
1759
1760 case IOCTL_DISK_GET_LENGTH_INFO: {
1761
1762 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1763 sizeof(GET_LENGTH_INFORMATION)) {
1764 status = STATUS_BUFFER_TOO_SMALL;
1765 Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION);
1766 break;
1767 }
1768 IoMarkIrpPending(Irp);
1769 IoStartPacket(DeviceObject, Irp, NULL, NULL);
1770 return STATUS_PENDING;
1771 }
1772
1773 case IOCTL_CDROM_GET_CONFIGURATION: {
1774
1775 PGET_CONFIGURATION_IOCTL_INPUT inputBuffer;
1776
1777 TraceLog((CdromDebugTrace,
1778 "IOCTL_CDROM_GET_CONFIGURATION to via irp %p\n", Irp));
1779
1780 //
1781 // Validate buffer length.
1782 //
1783
1784 if (irpStack->Parameters.DeviceIoControl.InputBufferLength !=
1785 sizeof(GET_CONFIGURATION_IOCTL_INPUT)) {
1786 status = STATUS_INFO_LENGTH_MISMATCH;
1787 break;
1788 }
1789 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1790 sizeof(GET_CONFIGURATION_HEADER)) {
1791 status = STATUS_BUFFER_TOO_SMALL;
1792 Irp->IoStatus.Information = sizeof(GET_CONFIGURATION_HEADER);
1793 break;
1794 }
1795 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength > 0xffff) {
1796 // output buffer is too large
1797 status = STATUS_INVALID_BUFFER_SIZE;
1798 break;
1799 }
1800
1801 //
1802 // also verify the arguments are reasonable.
1803 //
1804
1805 inputBuffer = Irp->AssociatedIrp.SystemBuffer;
1806 if (inputBuffer->Feature > 0xffff) {
1807 status = STATUS_INVALID_PARAMETER;
1808 break;
1809 }
1810 if ((inputBuffer->RequestType != SCSI_GET_CONFIGURATION_REQUEST_TYPE_ONE) &&
1811 (inputBuffer->RequestType != SCSI_GET_CONFIGURATION_REQUEST_TYPE_CURRENT) &&
1812 (inputBuffer->RequestType != SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL)) {
1813 status = STATUS_INVALID_PARAMETER;
1814 break;
1815 }
1816 if (inputBuffer->Reserved[0] || inputBuffer->Reserved[1]) {
1817 status = STATUS_INVALID_PARAMETER;
1818 break;
1819 }
1820
1821 IoMarkIrpPending(Irp);
1822 IoStartPacket(DeviceObject, Irp, NULL, NULL);
1823 return STATUS_PENDING;
1824
1825 }
1826
1827 default: {
1828
1829 BOOLEAN synchronize = (KeGetCurrentIrql() == PASSIVE_LEVEL);
1830 PKEVENT deviceControlEvent;
1831
1832 //
1833 // If the ioctl has come in at passive level then we will synchronize
1834 // with our start-io routine when sending the ioctl. If the ioctl
1835 // has come in at a higher interrupt level and it was not handled
1836 // above then it's unlikely to be a request for the class DLL - however
1837 // we'll still use it's common code to forward the request through.
1838 //
1839
1840 if (synchronize) {
1841
1842 deviceControlEvent = ExAllocatePoolWithTag(NonPagedPool,
1843 sizeof(KEVENT),
1844 CDROM_TAG_DC_EVENT);
1845
1846 if (deviceControlEvent == NULL) {
1847
1848 //
1849 // must complete this irp unsuccessful here
1850 //
1851 status = STATUS_INSUFFICIENT_RESOURCES;
1852 break;
1853
1854 } else {
1855
1856 //PIO_STACK_LOCATION currentStack;
1857
1858 KeInitializeEvent(deviceControlEvent, NotificationEvent, FALSE);
1859
1860 //currentStack = IoGetCurrentIrpStackLocation(Irp);
1861 nextStack = IoGetNextIrpStackLocation(Irp);
1862
1863 //
1864 // Copy the stack down a notch
1865 //
1866
1867 IoCopyCurrentIrpStackLocationToNext(Irp);
1868
1869 IoSetCompletionRoutine(
1870 Irp,
1871 CdRomClassIoctlCompletion,
1872 deviceControlEvent,
1873 TRUE,
1874 TRUE,
1875 TRUE
1876 );
1877
1878 IoSetNextIrpStackLocation(Irp);
1879
1880 Irp->IoStatus.Status = STATUS_SUCCESS;
1881 Irp->IoStatus.Information = 0;
1882
1883 //
1884 // Override volume verifies on this stack location so that we
1885 // will be forced through the synchronization. Once this
1886 // location goes away we get the old value back
1887 //
1888
1889 SET_FLAG(nextStack->Flags, SL_OVERRIDE_VERIFY_VOLUME);
1890
1891 IoStartPacket(DeviceObject, Irp, NULL, NULL);
1892
1893 //
1894 // Wait for CdRomClassIoctlCompletion to set the event. This
1895 // ensures serialization remains intact for these unhandled device
1896 // controls.
1897 //
1898
1899 KeWaitForSingleObject(
1900 deviceControlEvent,
1901 Executive,
1902 KernelMode,
1903 FALSE,
1904 NULL);
1905
1906 ExFreePool(deviceControlEvent);
1907
1908 TraceLog((CdromDebugTrace,
1909 "CdRomDeviceControl: irp %p synchronized\n", Irp));
1910
1911 status = Irp->IoStatus.Status;
1912 }
1913
1914 } else {
1915 status = STATUS_SUCCESS;
1916 }
1917
1918 //
1919 // If an error occured then propagate that back up - we are no longer
1920 // guaranteed synchronization and the upper layers will have to
1921 // retry.
1922 //
1923 // If no error occured, call down to the class driver directly
1924 // then start up the next request.
1925 //
1926
1927 if (NT_SUCCESS(status)) {
1928
1929 UCHAR uniqueAddress;
1930
1931 //
1932 // The class device control routine will release the remove
1933 // lock for this Irp. We need to make sure we have one
1934 // available so that it's safe to call IoStartNextPacket
1935 //
1936
1937 if(synchronize) {
1938
1939 ClassAcquireRemoveLock(DeviceObject, (PIRP)&uniqueAddress);
1940
1941 }
1942
1943 status = ClassDeviceControl(DeviceObject, Irp);
1944
1945 if(synchronize) {
1946 KeRaiseIrql(DISPATCH_LEVEL, &irql);
1947 IoStartNextPacket(DeviceObject, FALSE);
1948 KeLowerIrql(irql);
1949 ClassReleaseRemoveLock(DeviceObject, (PIRP)&uniqueAddress);
1950 }
1951 return status;
1952
1953 }
1954
1955 //
1956 // an error occurred (either STATUS_INSUFFICIENT_RESOURCES from
1957 // attempting to synchronize or StartIo() error'd this one
1958 // out), so we need to finish the irp, which is
1959 // done at the end of this routine.
1960 //
1961 break;
1962
1963 } // end default case
1964
1965 } // end switch()
1966
1967 if (status == STATUS_VERIFY_REQUIRED) {
1968
1969 //
1970 // If the status is verified required and this request
1971 // should bypass verify required then retry the request.
1972 //
1973
1974 if (irpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME) {
1975
1976 status = STATUS_IO_DEVICE_ERROR;
1977 goto RetryControl;
1978
1979 }
1980 }
1981
1982 if (IoIsErrorUserInduced(status)) {
1983
1984 if (Irp->Tail.Overlay.Thread) {
1985 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
1986 }
1987
1988 }
1989
1990 //
1991 // Update IRP with completion status.
1992 //
1993
1994 Irp->IoStatus.Status = status;
1995
1996 //
1997 // Complete the request.
1998 //
1999
2000 ClassReleaseRemoveLock(DeviceObject, Irp);
2001 ClassCompleteRequest(DeviceObject, Irp, IO_DISK_INCREMENT);
2002 TraceLog((CdromDebugTrace,
2003 "CdRomDeviceControl: Status is %lx\n", status));
2004 return status;
2005
2006 } // end CdRomDeviceControl()
2007
2008 NTSTATUS
2009 NTAPI
2010 CdRomClassIoctlCompletion(
2011 IN PDEVICE_OBJECT DeviceObject,
2012 IN PIRP Irp,
2013 IN PVOID Context
2014 )
2015 /*++
2016
2017 Routine Description:
2018
2019 This routine signals the event used by CdRomDeviceControl to synchronize
2020 class driver (and lower level driver) ioctls with cdrom's startio routine.
2021 The irp completion is short-circuited so that CdRomDeviceControlDispatch
2022 can reissue it once it wakes up.
2023
2024 Arguments:
2025
2026 DeviceObject - the device object
2027 Irp - the request we are synchronizing
2028 Context - a PKEVENT that we need to signal
2029
2030 Return Value:
2031
2032 NTSTATUS
2033
2034 --*/
2035 {
2036 PKEVENT syncEvent = (PKEVENT) Context;
2037
2038 TraceLog((CdromDebugTrace,
2039 "CdRomClassIoctlCompletion: setting event for irp %p\n", Irp));
2040
2041 //
2042 // We released the lock when we completed this request. Reacquire it.
2043 //
2044
2045 ClassAcquireRemoveLock(DeviceObject, Irp);
2046
2047 KeSetEvent(syncEvent, IO_DISK_INCREMENT, FALSE);
2048
2049 return STATUS_MORE_PROCESSING_REQUIRED;
2050 }
2051
2052 NTSTATUS
2053 NTAPI
2054 CdRomDeviceControlCompletion(
2055 IN PDEVICE_OBJECT DeviceObject,
2056 IN PIRP Irp,
2057 IN PVOID Context
2058 )
2059 {
2060 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
2061 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
2062
2063 PCDROM_DATA cdData = (PCDROM_DATA)(commonExtension->DriverData);
2064 BOOLEAN use6Byte = TEST_FLAG(cdData->XAFlags, XA_USE_6_BYTE);
2065
2066 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
2067 PIO_STACK_LOCATION realIrpStack;
2068 PIO_STACK_LOCATION realIrpNextStack;
2069
2070 PSCSI_REQUEST_BLOCK srb = Context;
2071
2072 PIRP realIrp = NULL;
2073
2074 NTSTATUS status;
2075 BOOLEAN retry;
2076 ULONG retryCount;
2077
2078 //
2079 // Extract the 'real' irp from the irpstack.
2080 //
2081
2082 realIrp = (PIRP) irpStack->Parameters.Others.Argument2;
2083 realIrpStack = IoGetCurrentIrpStackLocation(realIrp);
2084 realIrpNextStack = IoGetNextIrpStackLocation(realIrp);
2085
2086 //
2087 // check that we've really got the correct irp
2088 //
2089
2090 ASSERT(realIrpNextStack->Parameters.Others.Argument3 == Irp);
2091
2092 //
2093 // Check SRB status for success of completing request.
2094 //
2095
2096 if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
2097
2098 ULONG retryInterval;
2099
2100 TraceLog((CdromDebugTrace,
2101 "CdRomDeviceControlCompletion: Irp %p, Srb %p Real Irp %p Status %lx\n",
2102 Irp,
2103 srb,
2104 realIrp,
2105 srb->SrbStatus));
2106
2107 //
2108 // Release the queue if it is frozen.
2109 //
2110
2111 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
2112 TraceLog((CdromDebugTrace,
2113 "CdRomDeviceControlCompletion: Releasing Queue\n"));
2114 ClassReleaseQueue(DeviceObject);
2115 }
2116
2117
2118 retry = ClassInterpretSenseInfo(DeviceObject,
2119 srb,
2120 irpStack->MajorFunction,
2121 irpStack->Parameters.DeviceIoControl.IoControlCode,
2122 MAXIMUM_RETRIES - ((ULONG)(ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1),
2123 &status,
2124 &retryInterval);
2125
2126 TraceLog((CdromDebugTrace,
2127 "CdRomDeviceControlCompletion: IRP will %sbe retried\n",
2128 (retry ? "" : "not ")));
2129
2130 //
2131 // Some of the Device Controls need special cases on non-Success status's.
2132 //
2133
2134 if (realIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
2135 if ((realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_GET_LAST_SESSION) ||
2136 (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_READ_TOC) ||
2137 (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_READ_TOC_EX) ||
2138 (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_GET_CONTROL) ||
2139 (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_GET_VOLUME)) {
2140
2141 if (status == STATUS_DATA_OVERRUN) {
2142 status = STATUS_SUCCESS;
2143 retry = FALSE;
2144 }
2145 }
2146
2147 if (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_READ_Q_CHANNEL) {
2148 PLAY_ACTIVE(fdoExtension) = FALSE;
2149 }
2150 }
2151
2152 //
2153 // If the status is verified required and the this request
2154 // should bypass verify required then retry the request.
2155 //
2156
2157 if (realIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
2158 status == STATUS_VERIFY_REQUIRED) {
2159
2160 // note: status gets overwritten here
2161 status = STATUS_IO_DEVICE_ERROR;
2162 retry = TRUE;
2163
2164 if (((realIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) ||
2165 (realIrpStack->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL)
2166 ) &&
2167 ((realIrpStack->Parameters.DeviceIoControl.IoControlCode ==
2168 IOCTL_CDROM_CHECK_VERIFY) ||
2169 (realIrpStack->Parameters.DeviceIoControl.IoControlCode ==
2170 IOCTL_STORAGE_CHECK_VERIFY) ||
2171 (realIrpStack->Parameters.DeviceIoControl.IoControlCode ==
2172 IOCTL_STORAGE_CHECK_VERIFY2) ||
2173 (realIrpStack->Parameters.DeviceIoControl.IoControlCode ==
2174 IOCTL_DISK_CHECK_VERIFY)
2175 )
2176 ) {
2177
2178 //
2179 // Update the geometry information, as the media could have
2180 // changed. The completion routine for this will complete
2181 // the real irp and start the next packet.
2182 //
2183
2184 if (srb) {
2185 if (srb->SenseInfoBuffer) {
2186 ExFreePool(srb->SenseInfoBuffer);
2187 }
2188 if (srb->DataBuffer) {
2189 ExFreePool(srb->DataBuffer);
2190 }
2191 ExFreePool(srb);
2192 srb = NULL;
2193 }
2194
2195 if (Irp->MdlAddress) {
2196 IoFreeMdl(Irp->MdlAddress);
2197 Irp->MdlAddress = NULL;
2198 }
2199
2200 IoFreeIrp(Irp);
2201 Irp = NULL;
2202
2203 status = CdRomUpdateCapacity(fdoExtension, realIrp, NULL);
2204 TraceLog((CdromDebugTrace,
2205 "CdRomDeviceControlCompletion: [%p] "
2206 "CdRomUpdateCapacity completed with status %lx\n",
2207 realIrp, status));
2208
2209 //
2210 // needed to update the capacity.
2211 // the irp's already handed off to CdRomUpdateCapacity().
2212 // we've already free'd the current irp.
2213 // nothing left to do in this code path.
2214 //
2215
2216 return STATUS_MORE_PROCESSING_REQUIRED;
2217
2218 } // end of ioctls to update capacity
2219
2220 }
2221
2222 //
2223 // get current retry count
2224 //
2225 retryCount = PtrToUlong(realIrpNextStack->Parameters.Others.Argument1);
2226
2227 if (retry && retryCount) {
2228
2229 //
2230 // update retry count
2231 //
2232 realIrpNextStack->Parameters.Others.Argument1 = UlongToPtr(retryCount-1);
2233
2234 if (((ULONG)(ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1)) {
2235
2236 //
2237 // Retry request.
2238 //
2239
2240 TraceLog((CdromDebugWarning,
2241 "Retry request %p - Calling StartIo\n", Irp));
2242
2243
2244 ExFreePool(srb->SenseInfoBuffer);
2245 if (srb->DataBuffer) {
2246 ExFreePool(srb->DataBuffer);
2247 }
2248 ExFreePool(srb);
2249 if (Irp->MdlAddress) {
2250 IoFreeMdl(Irp->MdlAddress);
2251 }
2252
2253 realIrpNextStack->Parameters.Others.Argument3 = (PVOID)-1;
2254 IoFreeIrp(Irp);
2255
2256 CdRomRetryRequest(fdoExtension, realIrp, retryInterval, FALSE);
2257 return STATUS_MORE_PROCESSING_REQUIRED;
2258 }
2259
2260 //
2261 // Exhausted retries. Fall through and complete the request with
2262 // the appropriate status.
2263 //
2264
2265 }
2266 } else {
2267
2268 //
2269 // Set status for successful request.
2270 //
2271
2272 status = STATUS_SUCCESS;
2273
2274 }
2275
2276
2277 if (NT_SUCCESS(status)) {
2278
2279 BOOLEAN b = FALSE;
2280
2281
2282 switch (realIrpStack->Parameters.DeviceIoControl.IoControlCode) {
2283
2284 case IOCTL_CDROM_GET_CONFIGURATION: {
2285 RtlMoveMemory(realIrp->AssociatedIrp.SystemBuffer,
2286 srb->DataBuffer,
2287 srb->DataTransferLength);
2288 realIrp->IoStatus.Information = srb->DataTransferLength;
2289 break;
2290 }
2291
2292 case IOCTL_DISK_GET_LENGTH_INFO: {
2293
2294 PGET_LENGTH_INFORMATION lengthInfo;
2295
2296 CdRomInterpretReadCapacity(DeviceObject,
2297 (PREAD_CAPACITY_DATA)srb->DataBuffer);
2298
2299 lengthInfo = (PGET_LENGTH_INFORMATION)realIrp->AssociatedIrp.SystemBuffer;
2300 lengthInfo->Length = commonExtension->PartitionLength;
2301 realIrp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION);
2302 status = STATUS_SUCCESS;
2303 break;
2304 }
2305
2306 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX:
2307 case IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX: {
2308
2309 PDISK_GEOMETRY_EX geometryEx;
2310
2311 CdRomInterpretReadCapacity(DeviceObject,
2312 (PREAD_CAPACITY_DATA)srb->DataBuffer);
2313
2314 geometryEx = (PDISK_GEOMETRY_EX)(realIrp->AssociatedIrp.SystemBuffer);
2315 geometryEx->DiskSize = commonExtension->PartitionLength;
2316 geometryEx->Geometry = fdoExtension->DiskGeometry;
2317 realIrp->IoStatus.Information =
2318 FIELD_OFFSET(DISK_GEOMETRY_EX, Data);
2319 break;
2320 }
2321
2322 case IOCTL_DISK_GET_DRIVE_GEOMETRY:
2323 case IOCTL_CDROM_GET_DRIVE_GEOMETRY: {
2324
2325 PDISK_GEOMETRY geometry;
2326
2327 CdRomInterpretReadCapacity(DeviceObject,
2328 (PREAD_CAPACITY_DATA)srb->DataBuffer);
2329
2330 geometry = (PDISK_GEOMETRY)(realIrp->AssociatedIrp.SystemBuffer);
2331 *geometry = fdoExtension->DiskGeometry;
2332 realIrp->IoStatus.Information = sizeof(DISK_GEOMETRY);
2333 break;
2334 }
2335
2336 case IOCTL_DISK_VERIFY: {
2337 //
2338 // nothing to do but return the status...
2339 //
2340 break;
2341 }
2342
2343 case IOCTL_DISK_CHECK_VERIFY:
2344 case IOCTL_STORAGE_CHECK_VERIFY:
2345 case IOCTL_CDROM_CHECK_VERIFY: {
2346
2347 if((realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_CHECK_VERIFY) &&
2348 (realIrpStack->Parameters.DeviceIoControl.OutputBufferLength)) {
2349
2350 *((PULONG)realIrp->AssociatedIrp.SystemBuffer) =
2351 commonExtension->PartitionZeroExtension->MediaChangeCount;
2352
2353 realIrp->IoStatus.Information = sizeof(ULONG);
2354 } else {
2355 realIrp->IoStatus.Information = 0;
2356 }
2357
2358 TraceLog((CdromDebugTrace,
2359 "CdRomDeviceControlCompletion: [%p] completing "
2360 "CHECK_VERIFY buddy irp %p\n", realIrp, Irp));
2361 break;
2362 }
2363
2364 case IOCTL_CDROM_READ_TOC_EX: {
2365
2366 if (srb->DataTransferLength < MINIMUM_CDROM_READ_TOC_EX_SIZE) {
2367 status = STATUS_INVALID_DEVICE_REQUEST;
2368 break;
2369 }
2370
2371 //
2372 // Copy the returned info into the user buffer.
2373 //
2374
2375 RtlMoveMemory(realIrp->AssociatedIrp.SystemBuffer,
2376 srb->DataBuffer,
2377 srb->DataTransferLength);
2378
2379 //
2380 // update information field.
2381 //
2382
2383 realIrp->IoStatus.Information = srb->DataTransferLength;
2384 break;
2385 }
2386
2387
2388 case IOCTL_CDROM_GET_LAST_SESSION:
2389 case IOCTL_CDROM_READ_TOC: {
2390
2391 //
2392 // Copy the returned info into the user buffer.
2393 //
2394
2395 RtlMoveMemory(realIrp->AssociatedIrp.SystemBuffer,
2396 srb->DataBuffer,
2397 srb->DataTransferLength);
2398
2399 //
2400 // update information field.
2401 //
2402
2403 realIrp->IoStatus.Information = srb->DataTransferLength;
2404 break;
2405 }
2406
2407 case IOCTL_DVD_READ_STRUCTURE: {
2408
2409 DVD_STRUCTURE_FORMAT format = ((PDVD_READ_STRUCTURE) realIrp->AssociatedIrp.SystemBuffer)->Format;
2410
2411 PDVD_DESCRIPTOR_HEADER header = realIrp->AssociatedIrp.SystemBuffer;
2412
2413 //FOUR_BYTE fourByte;
2414 //PTWO_BYTE twoByte;
2415 //UCHAR tmp;
2416
2417 TraceLog((CdromDebugTrace,
2418 "DvdDeviceControlCompletion - IOCTL_DVD_READ_STRUCTURE: completing irp %p (buddy %p)\n",
2419 Irp,
2420 realIrp));
2421
2422 TraceLog((CdromDebugTrace,
2423 "DvdDCCompletion - READ_STRUCTURE: descriptor format of %d\n", format));
2424
2425 RtlMoveMemory(header,
2426 srb->DataBuffer,
2427 srb->DataTransferLength);
2428
2429 //
2430 // Cook the data. There are a number of fields that really
2431 // should be byte-swapped for the caller.
2432 //
2433
2434 TraceLog((CdromDebugInfo,
2435 "DvdDCCompletion - READ_STRUCTURE:\n"
2436 "\tHeader at %p\n"
2437 "\tDvdDCCompletion - READ_STRUCTURE: data at %p\n"
2438 "\tDataBuffer was at %p\n"
2439 "\tDataTransferLength was %lx\n",
2440 header,
2441 header->Data,
2442 srb->DataBuffer,
2443 srb->DataTransferLength));
2444
2445 //
2446 // First the fields in the header
2447 //
2448
2449 TraceLog((CdromDebugInfo, "READ_STRUCTURE: header->Length %lx -> ",
2450 header->Length));
2451 REVERSE_SHORT(&header->Length);
2452 TraceLog((CdromDebugInfo, "%lx\n", header->Length));
2453
2454 //
2455 // Now the fields in the descriptor
2456 //
2457
2458 if(format == DvdPhysicalDescriptor) {
2459
2460 PDVD_LAYER_DESCRIPTOR layer = (PDVD_LAYER_DESCRIPTOR) &(header->Data[0]);
2461
2462 TraceLog((CdromDebugInfo, "READ_STRUCTURE: StartingDataSector %lx -> ",
2463 layer->StartingDataSector));
2464 REVERSE_LONG(&(layer->StartingDataSector));
2465 TraceLog((CdromDebugInfo, "%lx\n", layer->StartingDataSector));
2466
2467 TraceLog((CdromDebugInfo, "READ_STRUCTURE: EndDataSector %lx -> ",
2468 layer->EndDataSector));
2469 REVERSE_LONG(&(layer->EndDataSector));
2470 TraceLog((CdromDebugInfo, "%lx\n", layer->EndDataSector));
2471
2472 TraceLog((CdromDebugInfo, "READ_STRUCTURE: EndLayerZeroSector %lx -> ",
2473 layer->EndLayerZeroSector));
2474 REVERSE_LONG(&(layer->EndLayerZeroSector));
2475 TraceLog((CdromDebugInfo, "%lx\n", layer->EndLayerZeroSector));
2476 }
2477
2478 TraceLog((CdromDebugTrace, "Status is %lx\n", Irp->IoStatus.Status));
2479 TraceLog((CdromDebugTrace, "DvdDeviceControlCompletion - "
2480 "IOCTL_DVD_READ_STRUCTURE: data transfer length of %d\n",
2481 srb->DataTransferLength));
2482
2483 realIrp->IoStatus.Information = srb->DataTransferLength;
2484 break;
2485 }
2486
2487 case IOCTL_DVD_READ_KEY: {
2488
2489 PDVD_COPY_PROTECT_KEY copyProtectKey = realIrp->AssociatedIrp.SystemBuffer;
2490
2491 PCDVD_KEY_HEADER keyHeader = srb->DataBuffer;
2492 ULONG dataLength;
2493
2494 ULONG transferLength =
2495 srb->DataTransferLength -
2496 FIELD_OFFSET(CDVD_KEY_HEADER, Data);
2497
2498 //
2499 // Adjust the data length to ignore the two reserved bytes in the
2500 // header.
2501 //
2502
2503 dataLength = (keyHeader->DataLength[0] << 8) +
2504 keyHeader->DataLength[1];
2505 dataLength -= 2;
2506
2507 //
2508 // take the minimum of the transferred length and the
2509 // length as specified in the header.
2510 //
2511
2512 if(dataLength < transferLength) {
2513 transferLength = dataLength;
2514 }
2515
2516 TraceLog((CdromDebugTrace,
2517 "DvdDeviceControlCompletion: [%p] - READ_KEY with "
2518 "transfer length of (%d or %d) bytes\n",
2519 Irp,
2520 dataLength,
2521 srb->DataTransferLength - 2));
2522
2523 //
2524 // Copy the key data into the return buffer
2525 //
2526 if(copyProtectKey->KeyType == DvdTitleKey) {
2527
2528 RtlMoveMemory(copyProtectKey->KeyData,
2529 keyHeader->Data + 1,
2530 transferLength - 1);
2531 copyProtectKey->KeyData[transferLength - 1] = 0;
2532
2533 //
2534 // If this is a title key then we need to copy the CGMS flags
2535 // as well.
2536 //
2537 copyProtectKey->KeyFlags = *(keyHeader->Data);
2538
2539 } else {
2540
2541 RtlMoveMemory(copyProtectKey->KeyData,
2542 keyHeader->Data,
2543 transferLength);
2544 }
2545
2546 copyProtectKey->KeyLength = sizeof(DVD_COPY_PROTECT_KEY);
2547 copyProtectKey->KeyLength += transferLength;
2548
2549 realIrp->IoStatus.Information = copyProtectKey->KeyLength;
2550 break;
2551 }
2552
2553 case IOCTL_DVD_START_SESSION: {
2554
2555 PDVD_SESSION_ID sessionId = realIrp->AssociatedIrp.SystemBuffer;
2556
2557 PCDVD_KEY_HEADER keyHeader = srb->DataBuffer;
2558 PCDVD_REPORT_AGID_DATA keyData = (PCDVD_REPORT_AGID_DATA) keyHeader->Data;
2559
2560 *sessionId = keyData->AGID;
2561
2562 realIrp->IoStatus.Information = sizeof(DVD_SESSION_ID);
2563
2564 break;
2565 }
2566
2567 case IOCTL_DVD_END_SESSION:
2568 case IOCTL_DVD_SEND_KEY:
2569 case IOCTL_DVD_SEND_KEY2:
2570
2571 //
2572 // nothing to return
2573 //
2574 realIrp->IoStatus.Information = 0;
2575 break;
2576
2577 case IOCTL_CDROM_PLAY_AUDIO_MSF:
2578
2579 PLAY_ACTIVE(fdoExtension) = TRUE;
2580
2581 break;
2582
2583 case IOCTL_CDROM_READ_Q_CHANNEL: {
2584
2585 PSUB_Q_CHANNEL_DATA userChannelData = realIrp->AssociatedIrp.SystemBuffer;
2586 PCDROM_SUB_Q_DATA_FORMAT inputBuffer = realIrp->AssociatedIrp.SystemBuffer;
2587 PSUB_Q_CHANNEL_DATA subQPtr = srb->DataBuffer;
2588
2589 #if DBG
2590 switch( inputBuffer->Format ) {
2591
2592 case IOCTL_CDROM_CURRENT_POSITION:
2593 TraceLog((CdromDebugTrace,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr->CurrentPosition.Header.AudioStatus ));
2594 TraceLog((CdromDebugTrace,"CdRomDeviceControlCompletion: ADR = 0x%x\n", subQPtr->CurrentPosition.ADR ));
2595 TraceLog((CdromDebugTrace,"CdRomDeviceControlCompletion: Control = 0x%x\n", subQPtr->CurrentPosition.Control ));
2596 TraceLog((CdromDebugTrace,"CdRomDeviceControlCompletion: Track = %u\n", subQPtr->CurrentPosition.TrackNumber ));
2597 TraceLog((CdromDebugTrace,"CdRomDeviceControlCompletion: Index = %u\n", subQPtr->CurrentPosition.IndexNumber ));
2598 TraceLog((CdromDebugTrace,"CdRomDeviceControlCompletion: Absolute Address = %x\n", *((PULONG)subQPtr->CurrentPosition.AbsoluteAddress) ));
2599 TraceLog((CdromDebugTrace,"CdRomDeviceControlCompletion: Relative Address = %x\n", *((PULONG)subQPtr->CurrentPosition.TrackRelativeAddress) ));
2600 break;
2601
2602 case IOCTL_CDROM_MEDIA_CATALOG:
2603 TraceLog((CdromDebugTrace,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr->MediaCatalog.Header.AudioStatus ));
2604 TraceLog((CdromDebugTrace,"CdRomDeviceControlCompletion: Mcval is %u\n", subQPtr->MediaCatalog.Mcval ));
2605 break;
2606
2607 case IOCTL_CDROM_TRACK_ISRC:
2608 TraceLog((CdromDebugTrace,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr->TrackIsrc.Header.AudioStatus ));
2609 TraceLog((CdromDebugTrace,"CdRomDeviceControlCompletion: Tcval is %u\n", subQPtr->TrackIsrc.Tcval ));
2610 break;
2611
2612 }
2613 #endif
2614
2615 //
2616 // Update the play active status.
2617 //
2618
2619 if (subQPtr->CurrentPosition.Header.AudioStatus == AUDIO_STATUS_IN_PROGRESS) {
2620
2621 PLAY_ACTIVE(fdoExtension) = TRUE;
2622
2623 } else {
2624
2625 PLAY_ACTIVE(fdoExtension) = FALSE;
2626
2627 }
2628
2629 //
2630 // Check if output buffer is large enough to contain
2631 // the data.
2632 //
2633
2634 if (realIrpStack->Parameters.DeviceIoControl.OutputBufferLength <
2635 srb->DataTransferLength) {
2636
2637 srb->DataTransferLength =
2638 realIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
2639 }
2640
2641 //
2642 // Copy our buffer into users.
2643 //
2644
2645 RtlMoveMemory(userChannelData,
2646 subQPtr,
2647 srb->DataTransferLength);
2648
2649 realIrp->IoStatus.Information = srb->DataTransferLength;
2650 break;
2651 }
2652
2653 case IOCTL_CDROM_PAUSE_AUDIO:
2654
2655 PLAY_ACTIVE(fdoExtension) = FALSE;
2656 realIrp->IoStatus.Information = 0;
2657 break;
2658
2659 case IOCTL_CDROM_RESUME_AUDIO:
2660
2661 realIrp->IoStatus.Information = 0;
2662 break;
2663
2664 case IOCTL_CDROM_SEEK_AUDIO_MSF:
2665
2666 realIrp->IoStatus.Information = 0;
2667 break;
2668
2669 case IOCTL_CDROM_STOP_AUDIO:
2670
2671 PLAY_ACTIVE(fdoExtension) = FALSE;
2672 realIrp->IoStatus.Information = 0;
2673 break;
2674
2675 case IOCTL_CDROM_GET_CONTROL: {
2676
2677 PCDROM_AUDIO_CONTROL audioControl = srb->DataBuffer;
2678 PAUDIO_OUTPUT audioOutput;
2679 ULONG bytesTransferred;
2680
2681 audioOutput = ClassFindModePage((PCHAR)audioControl,
2682 srb->DataTransferLength,
2683 CDROM_AUDIO_CONTROL_PAGE,
2684 use6Byte);
2685 //
2686 // Verify the page is as big as expected.
2687 //
2688
2689 bytesTransferred = (ULONG)((PCHAR) audioOutput - (PCHAR) audioControl) +
2690 sizeof(AUDIO_OUTPUT);
2691
2692 if (audioOutput != NULL &&
2693 srb->DataTransferLength >= bytesTransferred) {
2694
2695 audioControl->LbaFormat = audioOutput->LbaFormat;
2696
2697 audioControl->LogicalBlocksPerSecond =
2698 (audioOutput->LogicalBlocksPerSecond[0] << (UCHAR)8) |
2699 audioOutput->LogicalBlocksPerSecond[1];
2700
2701 realIrp->IoStatus.Information = sizeof(CDROM_AUDIO_CONTROL);
2702
2703 } else {
2704 realIrp->IoStatus.Information = 0;
2705 status = STATUS_INVALID_DEVICE_REQUEST;
2706 }
2707 break;
2708 }
2709
2710 case IOCTL_CDROM_GET_VOLUME: {
2711
2712 PAUDIO_OUTPUT audioOutput;
2713 PVOLUME_CONTROL volumeControl = srb->DataBuffer;
2714 ULONG i;
2715 ULONG bytesTransferred;
2716
2717 audioOutput = ClassFindModePage((PCHAR)volumeControl,
2718 srb->DataTransferLength,
2719 CDROM_AUDIO_CONTROL_PAGE,
2720 use6Byte);
2721
2722 //
2723 // Verify the page is as big as expected.
2724 //
2725
2726 bytesTransferred = (ULONG)((PCHAR) audioOutput - (PCHAR) volumeControl) +
2727 sizeof(AUDIO_OUTPUT);
2728
2729 if (audioOutput != NULL &&
2730 srb->DataTransferLength >= bytesTransferred) {
2731
2732 for (i=0; i<4; i++) {
2733 volumeControl->PortVolume[i] =
2734 audioOutput->PortOutput[i].Volume;
2735 }
2736
2737 //
2738 // Set bytes transferred in IRP.
2739 //
2740
2741 realIrp->IoStatus.Information = sizeof(VOLUME_CONTROL);
2742
2743 } else {
2744 realIrp->IoStatus.Information = 0;
2745 status = STATUS_INVALID_DEVICE_REQUEST;
2746 }
2747
2748 break;
2749 }
2750
2751 case IOCTL_CDROM_SET_VOLUME:
2752
2753 realIrp->IoStatus.Information = 0;
2754 break;
2755
2756 default:
2757
2758 ASSERT(FALSE);
2759 realIrp->IoStatus.Information = 0;
2760 status = STATUS_INVALID_DEVICE_REQUEST;
2761
2762 } // end switch()
2763 }
2764
2765 //
2766 // Deallocate srb and sense buffer.
2767 //
2768
2769 if (srb) {
2770 if (srb->DataBuffer) {
2771 ExFreePool(srb->DataBuffer);
2772 }
2773 if (srb->SenseInfoBuffer) {
2774 ExFreePool(srb->SenseInfoBuffer);
2775 }
2776 ExFreePool(srb);
2777 }
2778
2779 if (realIrp->PendingReturned) {
2780 IoMarkIrpPending(realIrp);
2781 }
2782
2783 if (Irp->MdlAddress) {
2784 IoFreeMdl(Irp->MdlAddress);
2785 }
2786
2787 IoFreeIrp(Irp);
2788
2789 //
2790 // Set status in completing IRP.
2791 //
2792
2793 realIrp->IoStatus.Status = status;
2794
2795 //
2796 // Set the hard error if necessary.
2797 //
2798
2799 if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
2800
2801 //
2802 // Store DeviceObject for filesystem, and clear
2803 // in IoStatus.Information field.
2804 //
2805
2806 TraceLog((CdromDebugWarning,
2807 "CdRomDeviceCompletion - Setting Hard Error on realIrp %p\n",
2808 realIrp));
2809 if (realIrp->Tail.Overlay.Thread) {
2810 IoSetHardErrorOrVerifyDevice(realIrp, DeviceObject);
2811 }
2812
2813 realIrp->IoStatus.Information = 0;
2814 }
2815
2816 //
2817 // note: must complete the realIrp, as the completed irp (above)
2818 // was self-allocated.
2819 //
2820
2821 CdRomCompleteIrpAndStartNextPacketSafely(DeviceObject, realIrp);
2822 return STATUS_MORE_PROCESSING_REQUIRED;
2823 }
2824
2825 NTSTATUS
2826 NTAPI
2827 CdRomSetVolumeIntermediateCompletion(
2828 IN PDEVICE_OBJECT DeviceObject,
2829 IN PIRP Irp,
2830 IN PVOID Context
2831 )
2832 {
2833 PFUNCTIONAL_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
2834 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
2835
2836 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
2837 PCDROM_DATA cdData = (PCDROM_DATA)(commonExtension->DriverData);
2838 BOOLEAN use6Byte = TEST_FLAG(cdData->XAFlags, XA_USE_6_BYTE);
2839 PIO_STACK_LOCATION realIrpStack;
2840 PIO_STACK_LOCATION realIrpNextStack;
2841 PSCSI_REQUEST_BLOCK srb = Context;
2842 PIRP realIrp = NULL;
2843 NTSTATUS status;
2844 BOOLEAN retry;
2845 ULONG retryCount;
2846
2847 //
2848 // Extract the 'real' irp from the irpstack.
2849 //
2850
2851 realIrp = (PIRP) irpStack->Parameters.Others.Argument2;
2852 realIrpStack = IoGetCurrentIrpStackLocation(realIrp);
2853 realIrpNextStack = IoGetNextIrpStackLocation(realIrp);
2854
2855 //
2856 // Check SRB status for success of completing request.
2857 //
2858
2859 if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
2860
2861 ULONG retryInterval;
2862
2863 TraceLog((CdromDebugTrace,
2864 "CdRomSetVolumeIntermediateCompletion: Irp %p, Srb %p, Real Irp %p\n",
2865 Irp,
2866 srb,
2867 realIrp));
2868
2869 //
2870 // Release the queue if it is frozen.
2871 //
2872
2873 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
2874 ClassReleaseQueue(DeviceObject);
2875 }
2876
2877
2878 retry = ClassInterpretSenseInfo(DeviceObject,
2879 srb,
2880 irpStack->MajorFunction,
2881 irpStack->Parameters.DeviceIoControl.IoControlCode,
2882 MAXIMUM_RETRIES - ((ULONG)(ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1),
2883 &status,
2884 &retryInterval);
2885
2886 if (status == STATUS_DATA_OVERRUN) {
2887 status = STATUS_SUCCESS;
2888 retry = FALSE;
2889 }
2890
2891 //
2892 // If the status is verified required and the this request
2893 // should bypass verify required then retry the request.
2894 //
2895
2896 if (realIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
2897 status == STATUS_VERIFY_REQUIRED) {
2898
2899 status = STATUS_IO_DEVICE_ERROR;
2900 retry = TRUE;
2901 }
2902
2903 //
2904 // get current retry count
2905 //
2906 retryCount = PtrToUlong(realIrpNextStack->Parameters.Others.Argument1);
2907
2908 if (retry && retryCount) {
2909
2910 //
2911 // update retry count
2912 //
2913 realIrpNextStack->Parameters.Others.Argument1 = UlongToPtr(retryCount-1);
2914
2915
2916 if (((ULONG)(ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1)) {
2917
2918 //
2919 // Retry request.
2920 //
2921
2922 TraceLog((CdromDebugWarning,
2923 "Retry request %p - Calling StartIo\n", Irp));
2924
2925
2926 ExFreePool(srb->SenseInfoBuffer);
2927 ExFreePool(srb->DataBuffer);
2928 ExFreePool(srb);
2929 if (Irp->MdlAddress) {
2930 IoFreeMdl(Irp->MdlAddress);
2931 }
2932
2933 IoFreeIrp(Irp);
2934
2935 CdRomRetryRequest(deviceExtension,
2936 realIrp,
2937 retryInterval,
2938 FALSE);
2939
2940 return STATUS_MORE_PROCESSING_REQUIRED;
2941
2942 }
2943
2944 //
2945 // Exhausted retries. Fall through and complete the request with the appropriate status.
2946 //
2947
2948 }
2949 } else {
2950
2951 //
2952 // Set status for successful request.
2953 //
2954
2955 status = STATUS_SUCCESS;
2956
2957 }
2958
2959 if (NT_SUCCESS(status)) {
2960
2961 PAUDIO_OUTPUT audioInput = NULL;
2962 PAUDIO_OUTPUT audioOutput;
2963 PVOLUME_CONTROL volumeControl = realIrp->AssociatedIrp.SystemBuffer;
2964 ULONG i,bytesTransferred,headerLength;
2965 PVOID dataBuffer;
2966 PCDB cdb;
2967
2968 audioInput = ClassFindModePage((PCHAR)srb->DataBuffer,
2969 srb->DataTransferLength,
2970 CDROM_AUDIO_CONTROL_PAGE,
2971 use6Byte);
2972
2973 //
2974 // Check to make sure the mode sense data is valid before we go on
2975 //
2976
2977 if(audioInput == NULL) {
2978
2979 TraceLog((CdromDebugWarning,
2980 "Mode Sense Page %d not found\n",
2981 CDROM_AUDIO_CONTROL_PAGE));
2982
2983 realIrp->IoStatus.Information = 0;
2984 realIrp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
2985 goto SafeExit;
2986 }
2987
2988 if (use6Byte) {
2989 headerLength = sizeof(MODE_PARAMETER_HEADER);
2990 } else {
2991 headerLength = sizeof(MODE_PARAMETER_HEADER10);
2992 }
2993
2994 bytesTransferred = sizeof(AUDIO_OUTPUT) + headerLength;
2995
2996 //
2997 // Allocate a new buffer for the mode select.
2998 //
2999
3000 dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
3001 bytesTransferred,
3002 CDROM_TAG_VOLUME_INT);
3003
3004 if (!dataBuffer) {
3005 realIrp->IoStatus.Information = 0;
3006 realIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
3007 goto SafeExit;
3008 }
3009
3010 RtlZeroMemory(dataBuffer, bytesTransferred);
3011
3012 //
3013 // Rebuild the data buffer to include the user requested values.
3014 //
3015
3016 audioOutput = (PAUDIO_OUTPUT) ((PCHAR) dataBuffer + headerLength);
3017
3018 for (i=0; i<4; i++) {
3019 audioOutput->PortOutput[i].Volume =
3020 volumeControl->PortVolume[i];
3021 audioOutput->PortOutput[i].ChannelSelection =
3022 audioInput->PortOutput[i].ChannelSelection;
3023 }
3024
3025 audioOutput->CodePage = CDROM_AUDIO_CONTROL_PAGE;
3026 audioOutput->ParameterLength = sizeof(AUDIO_OUTPUT) - 2;
3027 audioOutput->Immediate = MODE_SELECT_IMMEDIATE;
3028
3029 //
3030 // Free the old data buffer, mdl.
3031 //
3032
3033 IoFreeMdl(Irp->MdlAddress);
3034 Irp->MdlAddress = NULL;
3035 ExFreePool(srb->DataBuffer);
3036
3037 //
3038 // set the data buffer to new allocation, so it can be
3039 // freed in the exit path
3040 //
3041
3042 srb->DataBuffer = dataBuffer;
3043
3044 //
3045 // rebuild the srb.
3046 //
3047
3048 cdb = (PCDB)srb->Cdb;
3049 RtlZeroMemory(cdb, CDB12GENERIC_LENGTH);
3050
3051 srb->SrbStatus = srb->ScsiStatus = 0;
3052 srb->SrbFlags = deviceExtension->SrbFlags;
3053 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
3054 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_OUT);
3055 srb->DataTransferLength = bytesTransferred;
3056
3057 if (use6Byte) {
3058
3059 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
3060 cdb->MODE_SELECT.ParameterListLength = (UCHAR) bytesTransferred;
3061 cdb->MODE_SELECT.PFBit = 1;
3062 srb->CdbLength = 6;
3063 } else {
3064
3065 cdb->MODE_SELECT10.OperationCode = SCSIOP_MODE_SELECT10;
3066 cdb->MODE_SELECT10.ParameterListLength[0] = (UCHAR) (bytesTransferred >> 8);
3067 cdb->MODE_SELECT10.ParameterListLength[1] = (UCHAR) (bytesTransferred & 0xFF);
3068 cdb->MODE_SELECT10.PFBit = 1;
3069 srb->CdbLength = 10;
3070 }
3071
3072 //
3073 // Prepare the MDL
3074 //
3075
3076 Irp->MdlAddress = IoAllocateMdl(dataBuffer,
3077 bytesTransferred,
3078 FALSE,
3079 FALSE,
3080 (PIRP) NULL);
3081
3082 if (!Irp->MdlAddress) {
3083 realIrp->IoStatus.Information = 0;
3084 realIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
3085 goto SafeExit;
3086 }
3087
3088 MmBuildMdlForNonPagedPool(Irp->MdlAddress);
3089
3090 irpStack = IoGetNextIrpStackLocation(Irp);
3091 irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
3092 irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
3093 irpStack->Parameters.Scsi.Srb = srb;
3094
3095 //
3096 // reset the irp completion.
3097 //
3098
3099 IoSetCompletionRoutine(Irp,
3100 CdRomDeviceControlCompletion,
3101 srb,
3102 TRUE,
3103 TRUE,
3104 TRUE);
3105 //
3106 // Call the port driver.
3107 //
3108
3109 IoCallDriver(commonExtension->LowerDeviceObject, Irp);
3110
3111 return STATUS_MORE_PROCESSING_REQUIRED;
3112 }
3113
3114 SafeExit:
3115
3116 //
3117 // Deallocate srb and sense buffer.
3118 //
3119
3120 if (srb) {
3121 if (srb->DataBuffer) {
3122 ExFreePool(srb->DataBuffer);
3123 }
3124 if (srb->SenseInfoBuffer) {
3125 ExFreePool(srb->SenseInfoBuffer);
3126 }
3127 ExFreePool(srb);
3128 }
3129
3130 if (Irp->PendingReturned) {
3131 IoMarkIrpPending(Irp);
3132 }
3133
3134 if (realIrp->PendingReturned) {
3135 IoMarkIrpPending(realIrp);
3136 }
3137
3138 if (Irp->MdlAddress) {
3139 IoFreeMdl(Irp->MdlAddress);
3140 }
3141
3142 IoFreeIrp(Irp);
3143
3144 //
3145 // Set status in completing IRP.
3146 //
3147
3148 realIrp->IoStatus.Status = status;
3149
3150 //
3151 // Set the hard error if necessary.
3152 //
3153
3154 if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
3155
3156 //
3157 // Store DeviceObject for filesystem, and clear
3158 // in IoStatus.Information field.
3159 //
3160
3161 if (realIrp->Tail.Overlay.Thread) {
3162 IoSetHardErrorOrVerifyDevice(realIrp, DeviceObject);
3163 }
3164 realIrp->IoStatus.Information = 0;
3165 }
3166
3167 CdRomCompleteIrpAndStartNextPacketSafely(DeviceObject, realIrp);
3168 return STATUS_MORE_PROCESSING_REQUIRED;
3169 }
3170
3171 NTSTATUS
3172 NTAPI
3173 CdRomDvdEndAllSessionsCompletion(
3174 IN PDEVICE_OBJECT DeviceObject,
3175 IN PIRP Irp,
3176 IN PVOID Context
3177 )
3178
3179 /*++
3180
3181 Routine Description:
3182
3183 This routine will setup the next stack location to issue an end session
3184 to the device. It will increment the session id in the system buffer
3185 and issue an END_SESSION for that AGID if the AGID is valid.
3186
3187 When the new AGID is > 3 this routine will complete the request.
3188
3189 Arguments:
3190
3191 DeviceObject - the device object for this drive
3192
3193 Irp - the request
3194
3195 Context - done
3196
3197 Return Value:
3198
3199 STATUS_MORE_PROCESSING_REQUIRED if there is another AGID to clear
3200 status otherwise.
3201
3202 --*/
3203
3204 {
3205 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
3206
3207 PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
3208
3209 PDVD_SESSION_ID sessionId = Irp->AssociatedIrp.SystemBuffer;
3210
3211 //NTSTATUS status;
3212
3213 if(++(*sessionId) > MAX_COPY_PROTECT_AGID) {
3214
3215 //
3216 // We're done here - just return success and let the io system
3217 // continue to complete it.
3218 //
3219
3220 return STATUS_SUCCESS;
3221
3222 }
3223
3224 IoCopyCurrentIrpStackLocationToNext(Irp);
3225
3226 IoSetCompletionRoutine(Irp,
3227 CdRomDvdEndAllSessionsCompletion,
3228 NULL,
3229 TRUE,
3230 FALSE,
3231 FALSE);
3232
3233 IoMarkIrpPending(Irp);
3234
3235 IoCallDriver(fdoExtension->CommonExtension.DeviceObject, Irp);
3236
3237 //
3238 // At this point we have to assume the irp may have already been
3239 // completed. Ignore the returned status and return.
3240 //
3241
3242 return STATUS_MORE_PROCESSING_REQUIRED;
3243 }
3244
3245 NTSTATUS
3246 NTAPI
3247 CdRomDvdReadDiskKeyCompletion(
3248 IN PDEVICE_OBJECT DeviceObject,
3249 IN PIRP Irp,
3250 IN PVOID Context
3251 )
3252
3253 /*++
3254
3255 Routine Description:
3256
3257 This routine handles the completion of a request to obtain the disk
3258 key from the dvd media. It will transform the raw 2K of key data into
3259 a DVD_COPY_PROTECT_KEY structure and copy back the saved key parameters
3260 from the context pointer before returning.
3261
3262 Arguments:
3263
3264 DeviceObject -
3265
3266 Irp -
3267
3268 Context - a DVD_COPY_PROTECT_KEY pointer which contains the key
3269 parameters handed down by the caller.
3270
3271 Return Value:
3272
3273 STATUS_SUCCESS;
3274
3275 --*/
3276
3277 {
3278 PDVD_COPY_PROTECT_KEY savedKey = Context;
3279
3280 PREAD_DVD_STRUCTURES_HEADER rawKey = Irp->AssociatedIrp.SystemBuffer;
3281 PDVD_COPY_PROTECT_KEY outputKey = Irp->AssociatedIrp.SystemBuffer;
3282
3283 if (NT_SUCCESS(Irp->IoStatus.Status)) {
3284
3285 //
3286 // Shift the data down to its new position.
3287 //
3288
3289 RtlMoveMemory(outputKey->KeyData,
3290 rawKey->Data,
3291 sizeof(DVD_DISK_KEY_DESCRIPTOR));
3292
3293 RtlCopyMemory(outputKey,
3294 savedKey,
3295 sizeof(DVD_COPY_PROTECT_KEY));
3296
3297 outputKey->KeyLength = DVD_DISK_KEY_LENGTH;
3298
3299 Irp->IoStatus.Information = DVD_DISK_KEY_LENGTH;
3300
3301 } else {
3302
3303 TraceLog((CdromDebugWarning,
3304 "DiskKey Failed with status %x, %p (%x) bytes\n",
3305 Irp->IoStatus.Status,
3306 (PVOID)Irp->IoStatus.Information,
3307 ((rawKey->Length[0] << 16) | rawKey->Length[1])
3308 ));
3309
3310 }
3311
3312 //
3313 // release the context block
3314 //
3315
3316 ExFreePool(Context);
3317
3318 return STATUS_SUCCESS;
3319 }
3320
3321 NTSTATUS
3322 NTAPI
3323 CdRomXACompletion(
3324 IN PDEVICE_OBJECT DeviceObject,
3325 IN PIRP Irp,
3326 IN PVOID Context
3327 )
3328
3329 /*++
3330
3331 Routine Description:
3332
3333 This routine executes when the port driver has completed a request.
3334 It looks at the SRB status in the completing SRB and if not success
3335 it checks for valid request sense buffer information. If valid, the
3336 info is used to update status with more precise message of type of
3337 error. This routine deallocates the SRB.
3338
3339 Arguments:
3340
3341 DeviceObject - Supplies the device object which represents the logical
3342 unit.
3343
3344 Irp - Supplies the Irp which has completed.
3345
3346 Context - Supplies a pointer to the SRB.
3347
3348 Return Value:
3349
3350 NT status
3351
3352 --*/
3353
3354 {
3355 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
3356 PSCSI_REQUEST_BLOCK srb = Context;
3357 PFUNCTIONAL_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3358 NTSTATUS status;
3359 BOOLEAN retry;
3360
3361 //
3362 // Check SRB status for success of completing request.
3363 //
3364
3365 if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
3366
3367 ULONG retryInterval;
3368
3369 TraceLog((CdromDebugTrace, "CdromXAComplete: IRP %p SRB %p Status %x\n",
3370 Irp, srb, srb->SrbStatus));
3371
3372 //
3373 // Release the queue if it is frozen.
3374 //
3375
3376 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
3377 ClassReleaseQueue(DeviceObject);
3378 }
3379
3380 retry = ClassInterpretSenseInfo(
3381 DeviceObject,
3382 srb,
3383 irpStack->MajorFunction,
3384 irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL ? irpStack->Parameters.DeviceIoControl.IoControlCode : 0,
3385 MAXIMUM_RETRIES - irpStack->MinorFunction, // HACKHACK - REF #0001
3386 &status,
3387 &retryInterval);
3388
3389 //
3390 // If the status is verified required and the this request
3391 // should bypass verify required then retry the request.
3392 //
3393
3394 if (irpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
3395 status == STATUS_VERIFY_REQUIRED) {
3396
3397 status = STATUS_IO_DEVICE_ERROR;
3398 retry = TRUE;
3399 }
3400
3401 if (retry) {
3402
3403 if (irpStack->MinorFunction != 0) { // HACKHACK - REF #0001
3404
3405 irpStack->MinorFunction--; // HACKHACK - REF #0001
3406
3407 //
3408 // Retry request.
3409 //
3410
3411 TraceLog((CdromDebugWarning,
3412 "CdRomXACompletion: Retry request %p (%x) - "
3413 "Calling StartIo\n", Irp, irpStack->MinorFunction));
3414
3415
3416 ExFreePool(srb->SenseInfoBuffer);
3417 ExFreePool(srb);
3418
3419 //
3420 // Call StartIo directly since IoStartNextPacket hasn't been called,
3421 // the serialisation is still intact.
3422 //
3423
3424 CdRomRetryRequest(deviceExtension,
3425 Irp,
3426 retryInterval,
3427 FALSE);
3428
3429 return STATUS_MORE_PROCESSING_REQUIRED;
3430
3431 }
3432
3433 //
3434 // Exhausted retries, fall through and complete the request
3435 // with the appropriate status
3436 //
3437
3438 TraceLog((CdromDebugWarning,
3439 "CdRomXACompletion: Retries exhausted for irp %p\n",
3440 Irp));
3441
3442 }
3443
3444 } else {
3445
3446 //
3447 // Set status for successful request.
3448 //
3449
3450 status = STATUS_SUCCESS;
3451
3452 } // end if (SRB_STATUS(srb->SrbStatus) ...
3453
3454 //
3455 // Return SRB to nonpaged pool.
3456 //
3457
3458 ExFreePool(srb->SenseInfoBuffer);
3459 ExFreePool(srb);
3460
3461 //
3462 // Set status in completing IRP.
3463 //
3464
3465 Irp->IoStatus.Status = status;
3466
3467 //
3468 // Set the hard error if necessary.
3469 //
3470
3471 if (!NT_SUCCESS(status) &&
3472 IoIsErrorUserInduced(status) &&
3473 Irp->Tail.Overlay.Thread != NULL ) {
3474
3475 //
3476 // Store DeviceObject for filesystem, and clear
3477 // in IoStatus.Information field.
3478 //
3479
3480 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
3481 Irp->IoStatus.Information = 0;
3482 }
3483
3484 //
3485 // If pending has be returned for this irp then mark the current stack as
3486 // pending.
3487 //
3488
3489 if (Irp->PendingReturned) {
3490 IoMarkIrpPending(Irp);
3491 }
3492
3493 {
3494 KIRQL oldIrql = KeRaiseIrqlToDpcLevel();
3495 IoStartNextPacket(DeviceObject, FALSE);
3496 KeLowerIrql(oldIrql);
3497 }
3498 ClassReleaseRemoveLock(DeviceObject, Irp);
3499
3500 return status;
3501 }
3502
3503 VOID
3504 NTAPI
3505 CdRomDeviceControlDvdReadStructure(
3506 IN PDEVICE_OBJECT Fdo,
3507 IN PIRP OriginalIrp,
3508 IN PIRP NewIrp,
3509 IN PSCSI_REQUEST_BLOCK Srb
3510 )
3511 {
3512 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(OriginalIrp);
3513 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
3514 PCDB cdb = (PCDB)Srb->Cdb;
3515 PVOID dataBuffer;
3516
3517 PDVD_READ_STRUCTURE request;
3518 USHORT dataLength;
3519 ULONG blockNumber;
3520 PFOUR_BYTE fourByte;
3521
3522 dataLength =
3523 (USHORT)currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
3524
3525 request = OriginalIrp->AssociatedIrp.SystemBuffer;
3526 blockNumber =
3527 (ULONG)(request->BlockByteOffset.QuadPart >> fdoExtension->SectorShift);
3528 fourByte = (PFOUR_BYTE) &blockNumber;
3529
3530 Srb->CdbLength = 12;
3531 Srb->TimeOutValue = fdoExtension->TimeOutValue;
3532 Srb->SrbFlags = fdoExtension->SrbFlags;
3533 SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DATA_IN);
3534
3535 cdb->READ_DVD_STRUCTURE.OperationCode = SCSIOP_READ_DVD_STRUCTURE;
3536 cdb->READ_DVD_STRUCTURE.RMDBlockNumber[0] = fourByte->Byte3;
3537 cdb->READ_DVD_STRUCTURE.RMDBlockNumber[1] = fourByte->Byte2;
3538 cdb->READ_DVD_STRUCTURE.RMDBlockNumber[2] = fourByte->Byte1;
3539 cdb->READ_DVD_STRUCTURE.RMDBlockNumber[3] = fourByte->Byte0;
3540 cdb->READ_DVD_STRUCTURE.LayerNumber = request->LayerNumber;
3541 cdb->READ_DVD_STRUCTURE.Format = (UCHAR)request->Format;
3542
3543 #if DBG
3544 {
3545 if ((UCHAR)request->Format > DvdMaxDescriptor) {
3546 TraceLog((CdromDebugWarning,
3547 "READ_DVD_STRUCTURE format %x = %s (%x bytes)\n",
3548 (UCHAR)request->Format,
3549 READ_DVD_STRUCTURE_FORMAT_STRINGS[DvdMaxDescriptor],
3550 dataLength
3551 ));
3552 } else {
3553 TraceLog((CdromDebugWarning,
3554 "READ_DVD_STRUCTURE format %x = %s (%x bytes)\n",
3555 (UCHAR)request->Format,
3556 READ_DVD_STRUCTURE_FORMAT_STRINGS[(UCHAR)request->Format],
3557 dataLength
3558 ));
3559 }
3560 }
3561 #endif // DBG
3562
3563 if (request->Format == DvdDiskKeyDescriptor) {
3564
3565 cdb->READ_DVD_STRUCTURE.AGID = (UCHAR) request->SessionId;
3566
3567 }
3568
3569 cdb->READ_DVD_STRUCTURE.AllocationLength[0] = (UCHAR)(dataLength >> 8);
3570 cdb->READ_DVD_STRUCTURE.AllocationLength[1] = (UCHAR)(dataLength & 0xff);
3571 Srb->DataTransferLength = dataLength;
3572
3573
3574
3575 dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
3576 dataLength,
3577 DVD_TAG_READ_STRUCTURE);
3578
3579 if (!dataBuffer) {
3580 ExFreePool(Srb->SenseInfoBuffer);
3581 ExFreePool(Srb);
3582 IoFreeIrp(NewIrp);
3583 OriginalIrp->IoStatus.Information = 0;
3584 OriginalIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
3585
3586 BAIL_OUT(OriginalIrp);
3587 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, OriginalIrp);
3588 return;
3589 }
3590 RtlZeroMemory(dataBuffer, dataLength);
3591
3592 NewIrp->MdlAddress = IoAllocateMdl(dataBuffer,
3593 currentIrpStack->Parameters.Read.Length,
3594 FALSE,
3595 FALSE,
3596 (PIRP) NULL);
3597
3598 if (NewIrp->MdlAddress == NULL) {
3599 ExFreePool(dataBuffer);
3600 ExFreePool(Srb->SenseInfoBuffer);
3601 ExFreePool(Srb);
3602 IoFreeIrp(NewIrp);
3603 OriginalIrp->IoStatus.Information = 0;
3604 OriginalIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
3605
3606 BAIL_OUT(OriginalIrp);
3607 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, OriginalIrp);
3608 return;
3609 }
3610
3611 //
3612 // Prepare the MDL
3613 //
3614
3615 MmBuildMdlForNonPagedPool(NewIrp->MdlAddress);
3616
3617 Srb->DataBuffer = dataBuffer;
3618
3619 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, NewIrp);
3620
3621 return;
3622 }
3623
3624 VOID
3625 NTAPI
3626 CdRomDeviceControlDvdEndSession(
3627 IN PDEVICE_OBJECT Fdo,
3628 IN PIRP OriginalIrp,
3629 IN PIRP NewIrp,
3630 IN PSCSI_REQUEST_BLOCK Srb
3631 )
3632 {
3633 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(OriginalIrp);
3634 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
3635 PCDB cdb = (PCDB)Srb->Cdb;
3636
3637 PDVD_SESSION_ID sessionId = OriginalIrp->AssociatedIrp.SystemBuffer;
3638
3639 Srb->CdbLength = 12;
3640 Srb->TimeOutValue = fdoExtension->TimeOutValue;
3641 Srb->SrbFlags = fdoExtension->SrbFlags;
3642 SET_FLAG(Srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER);
3643
3644 cdb->SEND_KEY.OperationCode = SCSIOP_SEND_KEY;
3645 cdb->SEND_KEY.AGID = (UCHAR) (*sessionId);
3646 cdb->SEND_KEY.KeyFormat = DVD_INVALIDATE_AGID;
3647
3648 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, NewIrp);
3649 return;
3650
3651 }
3652
3653 VOID
3654 NTAPI
3655 CdRomDeviceControlDvdStartSessionReadKey(
3656 IN PDEVICE_OBJECT Fdo,
3657 IN PIRP OriginalIrp,
3658 IN PIRP NewIrp,
3659 IN PSCSI_REQUEST_BLOCK Srb
3660 )
3661 {
3662 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(OriginalIrp);
3663 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
3664 PCDB cdb = (PCDB)Srb->Cdb;
3665 NTSTATUS status;
3666
3667 PDVD_COPY_PROTECT_KEY keyParameters;
3668 PCDVD_KEY_HEADER keyBuffer = NULL;
3669
3670 ULONG keyLength;
3671
3672 ULONG allocationLength;
3673 PFOUR_BYTE fourByte;
3674
3675 //
3676 // Both of these use REPORT_KEY commands.
3677 // Determine the size of the input buffer
3678 //
3679
3680 if(currentIrpStack->Parameters.DeviceIoControl.IoControlCode ==
3681 IOCTL_DVD_READ_KEY) {
3682
3683 keyParameters = OriginalIrp->AssociatedIrp.SystemBuffer;
3684
3685 keyLength = sizeof(CDVD_KEY_HEADER) +
3686 (currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength -
3687 sizeof(DVD_COPY_PROTECT_KEY));
3688 } else {
3689
3690 keyParameters = NULL;
3691 keyLength = sizeof(CDVD_KEY_HEADER) +
3692 sizeof(CDVD_REPORT_AGID_DATA);
3693 }
3694
3695 TRY {
3696
3697 keyBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
3698 keyLength,
3699 DVD_TAG_READ_KEY);
3700
3701 if(keyBuffer == NULL) {
3702
3703 TraceLog((CdromDebugWarning,
3704 "IOCTL_DVD_READ_KEY - couldn't allocate "
3705 "%d byte buffer for key\n",
3706 keyLength));
3707 status = STATUS_INSUFFICIENT_RESOURCES;
3708 LEAVE;
3709 }
3710
3711
3712 NewIrp->MdlAddress = IoAllocateMdl(keyBuffer,
3713 keyLength,
3714 FALSE,
3715 FALSE,
3716 (PIRP) NULL);
3717
3718 if(NewIrp->MdlAddress == NULL) {
3719
3720 TraceLog((CdromDebugWarning,
3721 "IOCTL_DVD_READ_KEY - couldn't create mdl\n"));
3722 status = STATUS_INSUFFICIENT_RESOURCES;
3723 LEAVE;
3724 }
3725
3726 MmBuildMdlForNonPagedPool(NewIrp->MdlAddress);
3727
3728 Srb->DataBuffer = keyBuffer;
3729 Srb->CdbLength = 12;
3730
3731 cdb->REPORT_KEY.OperationCode = SCSIOP_REPORT_KEY;
3732
3733 allocationLength = keyLength;
3734 fourByte = (PFOUR_BYTE) &allocationLength;
3735 cdb->REPORT_KEY.AllocationLength[0] = fourByte->Byte1;
3736 cdb->REPORT_KEY.AllocationLength[1] = fourByte->Byte0;
3737
3738 Srb->DataTransferLength = keyLength;
3739
3740 //
3741 // set the specific parameters....
3742 //
3743
3744 if(currentIrpStack->Parameters.DeviceIoControl.IoControlCode ==
3745 IOCTL_DVD_READ_KEY) {
3746
3747 if(keyParameters->KeyType == DvdTitleKey) {
3748
3749 ULONG logicalBlockAddress;
3750
3751 logicalBlockAddress = (ULONG)
3752 (keyParameters->Parameters.TitleOffset.QuadPart >>
3753 fdoExtension->SectorShift);
3754
3755 fourByte = (PFOUR_BYTE) &(logicalBlockAddress);
3756
3757 cdb->REPORT_KEY.LogicalBlockAddress[0] = fourByte->Byte3;
3758 cdb->REPORT_KEY.LogicalBlockAddress[1] = fourByte->Byte2;
3759 cdb->REPORT_KEY.LogicalBlockAddress[2] = fourByte->Byte1;
3760 cdb->REPORT_KEY.LogicalBlockAddress[3] = fourByte->Byte0;
3761 }
3762
3763 cdb->REPORT_KEY.KeyFormat = (UCHAR)keyParameters->KeyType;
3764 cdb->REPORT_KEY.AGID = (UCHAR) keyParameters->SessionId;
3765 TraceLog((CdromDebugWarning,
3766 "CdRomDvdReadKey => sending irp %p for irp %p (%s)\n",
3767 NewIrp, OriginalIrp, "READ_KEY"));
3768
3769 } else {
3770
3771 cdb->REPORT_KEY.KeyFormat = DVD_REPORT_AGID;
3772 cdb->REPORT_KEY.AGID = 0;
3773 TraceLog((CdromDebugWarning,
3774 "CdRomDvdReadKey => sending irp %p for irp %p (%s)\n",
3775 NewIrp, OriginalIrp, "START_SESSION"));
3776 }
3777
3778 Srb->TimeOutValue = fdoExtension->TimeOutValue;
3779 Srb->SrbFlags = fdoExtension->SrbFlags;
3780 SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DATA_IN);
3781
3782 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, NewIrp);
3783
3784 status = STATUS_SUCCESS;
3785
3786 } FINALLY {
3787
3788 if (!NT_SUCCESS(status)) {
3789
3790 //
3791 // An error occured during setup - free resources and
3792 // complete this request.
3793 //
3794 if (NewIrp->MdlAddress != NULL) {
3795 IoFreeMdl(NewIrp->MdlAddress);
3796 }
3797
3798 if (keyBuffer != NULL) {
3799 ExFreePool(keyBuffer);
3800 }
3801 ExFreePool(Srb->SenseInfoBuffer);
3802 ExFreePool(Srb);
3803 IoFreeIrp(NewIrp);
3804
3805 OriginalIrp->IoStatus.Information = 0;
3806 OriginalIrp->IoStatus.Status = status;
3807
3808 BAIL_OUT(OriginalIrp);
3809 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, OriginalIrp);
3810
3811 } // end !NT_SUCCESS
3812 }
3813 return;
3814 }
3815
3816 VOID
3817 NTAPI
3818 CdRomDeviceControlDvdSendKey(
3819 IN PDEVICE_OBJECT Fdo,
3820 IN PIRP OriginalIrp,
3821 IN PIRP NewIrp,
3822 IN PSCSI_REQUEST_BLOCK Srb
3823 )
3824 {
3825 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(OriginalIrp);
3826 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
3827 PCDB cdb = (PCDB)Srb->Cdb;
3828
3829 PDVD_COPY_PROTECT_KEY key;
3830 PCDVD_KEY_HEADER keyBuffer = NULL;
3831
3832 NTSTATUS status;
3833 ULONG keyLength;
3834 PFOUR_BYTE fourByte;
3835
3836 key = OriginalIrp->AssociatedIrp.SystemBuffer;
3837 keyLength = (key->KeyLength - sizeof(DVD_COPY_PROTECT_KEY)) +
3838 sizeof(CDVD_KEY_HEADER);
3839
3840 TRY {
3841
3842 keyBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
3843 keyLength,
3844 DVD_TAG_SEND_KEY);
3845
3846 if(keyBuffer == NULL) {
3847
3848 TraceLog((CdromDebugWarning,
3849 "IOCTL_DVD_SEND_KEY - couldn't allocate "
3850 "%d byte buffer for key\n",
3851 keyLength));
3852 status = STATUS_INSUFFICIENT_RESOURCES;
3853 LEAVE;
3854 }
3855
3856 RtlZeroMemory(keyBuffer, keyLength);
3857
3858 //
3859 // keylength is decremented here by two because the
3860 // datalength does not include the header, which is two
3861 // bytes. keylength is immediately incremented later
3862 // by the same amount.
3863 //
3864
3865 keyLength -= 2;
3866 fourByte = (PFOUR_BYTE) &keyLength;
3867 keyBuffer->DataLength[0] = fourByte->Byte1;
3868 keyBuffer->DataLength[1] = fourByte->Byte0;
3869 keyLength += 2;
3870
3871 //
3872 // copy the user's buffer to our own allocated buffer
3873 //
3874
3875 RtlMoveMemory(keyBuffer->Data,
3876 key->KeyData,
3877 key->KeyLength - sizeof(DVD_COPY_PROTECT_KEY));
3878
3879
3880 NewIrp->MdlAddress = IoAllocateMdl(keyBuffer,
3881 keyLength,
3882 FALSE,
3883 FALSE,
3884 (PIRP) NULL);
3885
3886 if(NewIrp->MdlAddress == NULL) {
3887 TraceLog((CdromDebugWarning,
3888 "IOCTL_DVD_SEND_KEY - couldn't create mdl\n"));
3889 status = STATUS_INSUFFICIENT_RESOURCES;
3890 LEAVE;
3891 }
3892
3893
3894 MmBuildMdlForNonPagedPool(NewIrp->MdlAddress);
3895
3896 Srb->CdbLength = 12;
3897 Srb->DataBuffer = keyBuffer;
3898 Srb->DataTransferLength = keyLength;
3899
3900 Srb->TimeOutValue = fdoExtension->TimeOutValue;
3901 Srb->SrbFlags = fdoExtension->SrbFlags;
3902 SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DATA_OUT);
3903
3904 cdb->REPORT_KEY.OperationCode = SCSIOP_SEND_KEY;
3905
3906 fourByte = (PFOUR_BYTE) &keyLength;
3907
3908 cdb->SEND_KEY.ParameterListLength[0] = fourByte->Byte1;
3909 cdb->SEND_KEY.ParameterListLength[1] = fourByte->Byte0;
3910 cdb->SEND_KEY.KeyFormat = (UCHAR)key->KeyType;
3911 cdb->SEND_KEY.AGID = (UCHAR) key->SessionId;
3912
3913 if (key->KeyType == DvdSetRpcKey) {
3914 TraceLog((CdromDebugWarning,
3915 "IOCTL_DVD_SEND_KEY - Setting RPC2 drive region\n"));
3916 } else {
3917 TraceLog((CdromDebugWarning,
3918 "IOCTL_DVD_SEND_KEY - key type %x\n", key->KeyType));
3919 }
3920
3921 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, NewIrp);
3922
3923 status = STATUS_SUCCESS;
3924
3925 } FINALLY {
3926
3927 if (!NT_SUCCESS(status)) {
3928
3929 //
3930 // An error occured during setup - free resources and
3931 // complete this request.
3932 //
3933
3934 if (NewIrp->MdlAddress != NULL) {
3935 IoFreeMdl(NewIrp->MdlAddress);
3936 }
3937
3938 if (keyBuffer != NULL) {
3939 ExFreePool(keyBuffer);
3940 }
3941
3942 ExFreePool(Srb->SenseInfoBuffer);
3943 ExFreePool(Srb);
3944 IoFreeIrp(NewIrp);
3945
3946 OriginalIrp->IoStatus.Information = 0;
3947 OriginalIrp->IoStatus.Status = status;
3948
3949 BAIL_OUT(OriginalIrp);
3950 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, OriginalIrp);
3951
3952 }
3953 }
3954
3955 return;
3956 }
3957
3958 VOID
3959 NTAPI
3960 CdRomInterpretReadCapacity(
3961 IN PDEVICE_OBJECT Fdo,
3962 IN PREAD_CAPACITY_DATA ReadCapacityBuffer
3963 )
3964 {
3965 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
3966 PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
3967 ULONG lastSector;
3968 ULONG bps;
3969 ULONG lastBit;
3970 ULONG tmp;
3971
3972 ASSERT(ReadCapacityBuffer);
3973 ASSERT(commonExtension->IsFdo);
3974
3975 TraceLog((CdromDebugError,
3976 "CdRomInterpretReadCapacity: Entering\n"));
3977
3978 //
3979 // Swizzle bytes from Read Capacity and translate into
3980 // the necessary geometry information in the device extension.
3981 //
3982
3983 tmp = ReadCapacityBuffer->BytesPerBlock;
3984 ((PFOUR_BYTE)&bps)->Byte0 = ((PFOUR_BYTE)&tmp)->Byte3;
3985 ((PFOUR_BYTE)&bps)->Byte1 = ((PFOUR_BYTE)&tmp)->Byte2;
3986 ((PFOUR_BYTE)&bps)->Byte2 = ((PFOUR_BYTE)&tmp)->Byte1;
3987 ((PFOUR_BYTE)&bps)->Byte3 = ((PFOUR_BYTE)&tmp)->Byte0;
3988
3989 //
3990 // Insure that bps is a power of 2.
3991 // This corrects a problem with the HP 4020i CDR where it
3992 // returns an incorrect number for bytes per sector.
3993 //
3994
3995 if (!bps) {
3996 bps = 2048;
3997 } else {
3998 lastBit = (ULONG) -1;
3999 while (bps) {
4000 lastBit++;
4001 bps = bps >> 1;
4002 }
4003 bps = 1 << lastBit;
4004 }
4005
4006 fdoExtension->DiskGeometry.BytesPerSector = bps;
4007
4008 TraceLog((CdromDebugTrace, "CdRomInterpretReadCapacity: Calculated bps %#x\n",
4009 fdoExtension->DiskGeometry.BytesPerSector));
4010
4011 //
4012 // Copy last sector in reverse byte order.
4013 //
4014
4015 tmp = ReadCapacityBuffer->LogicalBlockAddress;
4016 ((PFOUR_BYTE)&lastSector)->Byte0 = ((PFOUR_BYTE)&tmp)->Byte3;
4017 ((PFOUR_BYTE)&lastSector)->Byte1 = ((PFOUR_BYTE)&tmp)->Byte2;
4018 ((PFOUR_BYTE)&lastSector)->Byte2 = ((PFOUR_BYTE)&tmp)->Byte1;
4019 ((PFOUR_BYTE)&lastSector)->Byte3 = ((PFOUR_BYTE)&tmp)->Byte0;
4020
4021 //
4022 // Calculate sector to byte shift.
4023 //
4024
4025 WHICH_BIT(bps, fdoExtension->SectorShift);
4026
4027 TraceLog((CdromDebugTrace,"CdRomInterpretReadCapacity: Sector size is %d\n",
4028 fdoExtension->DiskGeometry.BytesPerSector));
4029
4030 TraceLog((CdromDebugTrace,"CdRomInterpretReadCapacity: Number of Sectors is %d\n",
4031 lastSector + 1));
4032
4033 //
4034 // Calculate media capacity in bytes.
4035 //
4036
4037 commonExtension->PartitionLength.QuadPart = (LONGLONG)(lastSector + 1);
4038
4039 //
4040 // we've defaulted to 32/64 forever. don't want to change this now...
4041 //
4042
4043 fdoExtension->DiskGeometry.TracksPerCylinder = 0x40;
4044 fdoExtension->DiskGeometry.SectorsPerTrack = 0x20;
4045
4046 //
4047 // Calculate number of cylinders.
4048 //
4049
4050 fdoExtension->DiskGeometry.Cylinders.QuadPart = (LONGLONG)((lastSector + 1) / (32 * 64));
4051
4052 commonExtension->PartitionLength.QuadPart =
4053 (commonExtension->PartitionLength.QuadPart << fdoExtension->SectorShift);
4054
4055
4056 ASSERT(TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA));
4057
4058 //
4059 // This device supports removable media.
4060 //
4061
4062 fdoExtension->DiskGeometry.MediaType = RemovableMedia;
4063
4064 return;
4065 }