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