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