cbf3efb612acb11944aae486643f947300f47e9f
[reactos.git] / drivers / storage / class / cdrom_new / cdrom.c
1 /*--
2
3 Copyright (C) Microsoft Corporation, 1991 - 1999
4
5 Module Name:
6
7 cdrom.c
8
9 Abstract:
10
11 The CDROM class driver tranlates IRPs to SRBs with embedded CDBs
12 and sends them to its devices through the port driver.
13
14 Environment:
15
16 kernel mode only
17
18 Notes:
19
20 SCSI Tape, CDRom and Disk class drivers share common routines
21 that can be found in the CLASS directory (..\ntos\dd\class).
22
23 Revision History:
24
25 --*/
26
27 #include "cdrom.h"
28
29 #ifdef ALLOC_PRAGMA
30
31 #pragma alloc_text(INIT, DriverEntry)
32
33 #pragma alloc_text(PAGE, CdRomUnload)
34 #pragma alloc_text(PAGE, CdRomAddDevice)
35 #pragma alloc_text(PAGE, CdRomCreateDeviceObject)
36 #pragma alloc_text(PAGE, CdRomStartDevice)
37 #pragma alloc_text(PAGE, ScanForSpecial)
38 #pragma alloc_text(PAGE, ScanForSpecialHandler)
39 #pragma alloc_text(PAGE, CdRomRemoveDevice)
40 #pragma alloc_text(PAGE, CdRomGetDeviceType)
41 #pragma alloc_text(PAGE, CdRomReadWriteVerification)
42 #pragma alloc_text(PAGE, CdRomGetDeviceParameter)
43 #pragma alloc_text(PAGE, CdRomSetDeviceParameter)
44 #pragma alloc_text(PAGE, CdRomPickDvdRegion)
45 #pragma alloc_text(PAGE, CdRomIsPlayActive)
46
47 #pragma alloc_text(PAGEHITA, HitachiProcessError)
48 #pragma alloc_text(PAGEHIT2, HitachiProcessErrorGD2000)
49
50 #pragma alloc_text(PAGETOSH, ToshibaProcessErrorCompletion)
51 #pragma alloc_text(PAGETOSH, ToshibaProcessError)
52
53 #endif
54
55 #define IS_WRITE_REQUEST(irpStack) \
56 (irpStack->MajorFunction == IRP_MJ_WRITE)
57
58 #define IS_READ_WRITE_REQUEST(irpStack) \
59 ((irpStack->MajorFunction == IRP_MJ_READ) || \
60 (irpStack->MajorFunction == IRP_MJ_WRITE) || \
61 ((irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) && \
62 (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_RAW_READ)))
63
64
65 NTSTATUS
66 NTAPI
67 DriverEntry(
68 IN PDRIVER_OBJECT DriverObject,
69 IN PUNICODE_STRING RegistryPath
70 )
71
72 /*++
73
74 Routine Description:
75
76 This routine initializes the cdrom class driver.
77
78 Arguments:
79
80 DriverObject - Pointer to driver object created by system.
81
82 RegistryPath - Pointer to the name of the services node for this driver.
83
84 Return Value:
85
86 The function value is the final status from the initialization operation.
87
88 --*/
89
90 {
91 CLASS_INIT_DATA InitializationData;
92 PCDROM_DRIVER_EXTENSION driverExtension;
93 NTSTATUS status;
94
95 PAGED_CODE();
96
97 WPP_INIT_TRACING(DriverObject, RegistryPath);
98
99 TraceLog((CdromDebugTrace,
100 "CDROM.SYS DriverObject %p loading\n", DriverObject));
101
102 status = IoAllocateDriverObjectExtension(DriverObject,
103 CDROM_DRIVER_EXTENSION_ID,
104 sizeof(CDROM_DRIVER_EXTENSION),
105 (PVOID*)&driverExtension);
106
107 if (!NT_SUCCESS(status)) {
108 TraceLog((CdromDebugWarning,
109 "DriverEntry !! no DriverObjectExtension %x\n", status));
110 return status;
111 }
112
113 //
114 // always zero the memory, since we are now reloading the driver.
115 //
116
117 RtlZeroMemory(driverExtension, sizeof(CDROM_DRIVER_EXTENSION));
118
119 //
120 // Zero InitData
121 //
122
123 RtlZeroMemory (&InitializationData, sizeof(CLASS_INIT_DATA));
124
125 //
126 // Set sizes
127 //
128
129 InitializationData.InitializationDataSize = sizeof(CLASS_INIT_DATA);
130
131 InitializationData.FdoData.DeviceExtensionSize = DEVICE_EXTENSION_SIZE;
132
133 InitializationData.FdoData.DeviceType = FILE_DEVICE_CD_ROM;
134 InitializationData.FdoData.DeviceCharacteristics =
135 FILE_REMOVABLE_MEDIA | FILE_DEVICE_SECURE_OPEN;
136
137 //
138 // Set entry points
139 //
140
141 InitializationData.FdoData.ClassError = CdRomErrorHandler;
142 InitializationData.FdoData.ClassInitDevice = CdRomInitDevice;
143 InitializationData.FdoData.ClassStartDevice = CdRomStartDevice;
144 InitializationData.FdoData.ClassStopDevice = CdRomStopDevice;
145 InitializationData.FdoData.ClassRemoveDevice = CdRomRemoveDevice;
146
147 InitializationData.FdoData.ClassReadWriteVerification = CdRomReadWriteVerification;
148 InitializationData.FdoData.ClassDeviceControl = CdRomDeviceControlDispatch;
149
150 InitializationData.FdoData.ClassPowerDevice = ClassSpinDownPowerHandler;
151 InitializationData.FdoData.ClassShutdownFlush = CdRomShutdownFlush;
152 InitializationData.FdoData.ClassCreateClose = NULL;
153
154 InitializationData.ClassStartIo = CdRomStartIo;
155 InitializationData.ClassAddDevice = CdRomAddDevice;
156
157 InitializationData.ClassTick = CdRomTickHandler;
158 InitializationData.ClassUnload = CdRomUnload;
159
160 //
161 // Call the class init routine
162 //
163 return ClassInitialize( DriverObject, RegistryPath, &InitializationData);
164
165 } // end DriverEntry()
166
167 VOID
168 NTAPI
169 CdRomUnload(
170 IN PDRIVER_OBJECT DriverObject
171 )
172 {
173 PAGED_CODE();
174 UNREFERENCED_PARAMETER(DriverObject);
175 TraceLog((CdromDebugTrace,
176 "CDROM.SYS DriverObject %p unloading\n", DriverObject));
177 WPP_CLEANUP(DriverObject);
178 return;
179 } // end CdRomUnload()
180
181 NTSTATUS
182 NTAPI
183 CdRomAddDevice(
184 IN PDRIVER_OBJECT DriverObject,
185 IN PDEVICE_OBJECT PhysicalDeviceObject
186 )
187
188 /*++
189
190 Routine Description:
191
192 This routine creates and initializes a new FDO for the corresponding
193 PDO. It may perform property queries on the FDO but cannot do any
194 media access operations.
195
196 Arguments:
197
198 DriverObject - CDROM class driver object.
199
200 Pdo - the physical device object we are being added to
201
202 Return Value:
203
204 status
205
206 --*/
207
208 {
209 NTSTATUS status;
210
211 PAGED_CODE();
212
213 //
214 // Get the address of the count of the number of cdroms already initialized.
215 //
216 DbgPrint("add device\n");
217
218 status = CdRomCreateDeviceObject(DriverObject,
219 PhysicalDeviceObject);
220
221 //
222 // Note: this always increments driver extension counter
223 // it will eventually wrap, and fail additions
224 // if an existing cdrom has the given number.
225 // so unlikely that we won't even bother considering
226 // this case, since the cure is quite likely worse
227 // than the symptoms.
228 //
229
230 if(NT_SUCCESS(status)) {
231
232 //
233 // keep track of the total number of active cdroms in IoGet(),
234 // as some programs use this to determine when they have found
235 // all the cdroms in the system.
236 //
237
238 TraceLog((CdromDebugTrace, "CDROM.SYS Add succeeded\n"));
239 IoGetConfigurationInformation()->CdRomCount++;
240
241 } else {
242
243 TraceLog((CdromDebugWarning,
244 "CDROM.SYS Add failed! %x\n", status));
245
246 }
247
248 return status;
249 }
250
251 NTSTATUS
252 NTAPI
253 CdRomCreateDeviceObject(
254 IN PDRIVER_OBJECT DriverObject,
255 IN PDEVICE_OBJECT PhysicalDeviceObject
256 )
257
258 /*++
259
260 Routine Description:
261
262 This routine creates an object for the device and then calls the
263 SCSI port driver for media capacity and sector size.
264
265 Arguments:
266
267 DriverObject - Pointer to driver object created by system.
268 PortDeviceObject - to connect to SCSI port driver.
269 DeviceCount - Number of previously installed CDROMs.
270 PortCapabilities - Pointer to structure returned by SCSI port
271 driver describing adapter capabilities (and limitations).
272 LunInfo - Pointer to configuration information for this device.
273
274 Return Value:
275
276 NTSTATUS
277
278 --*/
279 {
280 UCHAR ntNameBuffer[64];
281 //STRING ntNameString;
282 NTSTATUS status;
283
284 PDEVICE_OBJECT lowerDevice = NULL;
285 PDEVICE_OBJECT deviceObject = NULL;
286 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = NULL;
287 PCDROM_DATA cdData = NULL;
288 PCDROM_DRIVER_EXTENSION driverExtension = NULL;
289 ULONG deviceNumber;
290
291 //CCHAR dosNameBuffer[64];
292 //CCHAR deviceNameBuffer[64];
293 //STRING deviceNameString;
294 //STRING dosString;
295 //UNICODE_STRING dosUnicodeString;
296 //UNICODE_STRING unicodeString;
297
298 PAGED_CODE();
299
300 //
301 // Claim the device. Note that any errors after this
302 // will goto the generic handler, where the device will
303 // be released.
304 //
305
306 lowerDevice = IoGetAttachedDeviceReference(PhysicalDeviceObject);
307
308 status = ClassClaimDevice(lowerDevice, FALSE);
309
310 if(!NT_SUCCESS(status)) {
311
312 //
313 // Someone already had this device - we're in trouble
314 //
315
316 ObDereferenceObject(lowerDevice);
317 return status;
318 }
319
320 //
321 // Create device object for this device by first getting a unique name
322 // for the device and then creating it.
323 //
324
325 driverExtension = IoGetDriverObjectExtension(DriverObject,
326 CDROM_DRIVER_EXTENSION_ID);
327 ASSERT(driverExtension != NULL);
328
329 //
330 // InterlockedCdRomCounter is biased by 1.
331 //
332
333 deviceNumber = InterlockedIncrement(&driverExtension->InterlockedCdRomCounter) - 1;
334 sprintf(ntNameBuffer, "\\Device\\CdRom%d", deviceNumber);
335
336
337 status = ClassCreateDeviceObject(DriverObject,
338 ntNameBuffer,
339 PhysicalDeviceObject,
340 TRUE,
341 &deviceObject);
342
343 if (!NT_SUCCESS(status)) {
344 TraceLog((CdromDebugWarning,
345 "CreateCdRomDeviceObjects: Can not create device %s\n",
346 ntNameBuffer));
347
348 goto CreateCdRomDeviceObjectExit;
349 }
350
351 //
352 // Indicate that IRPs should include MDLs.
353 //
354
355 SET_FLAG(deviceObject->Flags, DO_DIRECT_IO);
356
357 fdoExtension = deviceObject->DeviceExtension;
358
359 //
360 // Back pointer to device object.
361 //
362
363 fdoExtension->CommonExtension.DeviceObject = deviceObject;
364
365 //
366 // This is the physical device.
367 //
368
369 fdoExtension->CommonExtension.PartitionZeroExtension = fdoExtension;
370
371 //
372 // Initialize lock count to zero. The lock count is used to
373 // disable the ejection mechanism when media is mounted.
374 //
375
376 fdoExtension->LockCount = 0;
377
378 //
379 // Save system cdrom number
380 //
381
382 fdoExtension->DeviceNumber = deviceNumber;
383
384 //
385 // Set the alignment requirements for the device based on the
386 // host adapter requirements
387 //
388
389 if (lowerDevice->AlignmentRequirement > deviceObject->AlignmentRequirement) {
390 deviceObject->AlignmentRequirement = lowerDevice->AlignmentRequirement;
391 }
392
393 //
394 // Save the device descriptors
395 //
396
397 fdoExtension->AdapterDescriptor = NULL;
398
399 fdoExtension->DeviceDescriptor = NULL;
400
401 //
402 // Clear the SrbFlags and disable synchronous transfers
403 //
404
405 fdoExtension->SrbFlags = SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
406
407 //
408 // Finally, attach to the PDO
409 //
410
411 fdoExtension->LowerPdo = PhysicalDeviceObject;
412
413 fdoExtension->CommonExtension.LowerDeviceObject =
414 IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject);
415
416 if(fdoExtension->CommonExtension.LowerDeviceObject == NULL) {
417
418 //
419 // Uh - oh, we couldn't attach
420 // cleanup and return
421 //
422
423 status = STATUS_UNSUCCESSFUL;
424 goto CreateCdRomDeviceObjectExit;
425 }
426
427 //
428 // CdRom uses an extra stack location for synchronizing it's start io
429 // routine
430 //
431
432 deviceObject->StackSize++;
433
434 //
435 // cdData is used a few times below
436 //
437
438 cdData = fdoExtension->CommonExtension.DriverData;
439
440 //
441 // For NTMS to be able to easily determine drives-drv. letter matches.
442 //
443
444 status = CdRomCreateWellKnownName( deviceObject );
445
446 if (!NT_SUCCESS(status)) {
447 TraceLog((CdromDebugWarning,
448 "CdromCreateDeviceObjects: unable to create symbolic "
449 "link for device %wZ\n", &fdoExtension->CommonExtension.DeviceName));
450 TraceLog((CdromDebugWarning,
451 "CdromCreateDeviceObjects: (non-fatal error)\n"));
452 }
453
454 ClassUpdateInformationInRegistry(deviceObject, "CdRom",
455 fdoExtension->DeviceNumber, NULL, 0);
456
457 //
458 // from above IoGetAttachedDeviceReference
459 //
460
461 ObDereferenceObject(lowerDevice);
462
463 //
464 // need to init timerlist here in case a remove occurs
465 // without a start, since we check the list is empty on remove.
466 //
467
468 cdData->DelayedRetryIrp = NULL;
469 cdData->DelayedRetryInterval = 0;
470
471 //
472 // need this to be initialized for RPC Phase 1 drives (rpc0)
473 //
474
475 KeInitializeMutex(&cdData->Rpc0RegionMutex, 0);
476
477 //
478 // The device is initialized properly - mark it as such.
479 //
480
481 CLEAR_FLAG(deviceObject->Flags, DO_DEVICE_INITIALIZING);
482
483 return(STATUS_SUCCESS);
484
485 CreateCdRomDeviceObjectExit:
486
487 //
488 // Release the device since an error occured.
489 //
490
491 // ClassClaimDevice(PortDeviceObject,
492 // LunInfo,
493 // TRUE,
494 // NULL);
495
496 //
497 // from above IoGetAttachedDeviceReference
498 //
499
500 ObDereferenceObject(lowerDevice);
501
502 if (deviceObject != NULL) {
503 IoDeleteDevice(deviceObject);
504 }
505
506 return status;
507
508 } // end CreateCdRomDeviceObject()
509
510 NTSTATUS
511 NTAPI
512 CdRomInitDevice(
513 IN PDEVICE_OBJECT Fdo
514 )
515
516 /*++
517
518 Routine Description:
519
520 This routine will complete the cd-rom initialization. This includes
521 allocating sense info buffers and srb s-lists, reading drive capacity
522 and setting up Media Change Notification (autorun).
523
524 This routine will not clean up allocate resources if it fails - that
525 is left for device stop/removal
526
527 Arguments:
528
529 Fdo - a pointer to the functional device object for this device
530
531 Return Value:
532
533 status
534
535 --*/
536
537 {
538 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
539 PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
540 #if 0
541 PCLASS_DRIVER_EXTENSION driverExtension = ClassGetDriverExtension(
542 Fdo->DriverObject);
543 #endif
544
545 PVOID senseData = NULL;
546
547 ULONG timeOut;
548 PCDROM_DATA cddata = NULL;
549
550 //BOOLEAN changerDevice;
551 BOOLEAN isMmcDevice = FALSE;
552
553 ULONG bps;
554 ULONG lastBit;
555
556
557 NTSTATUS status;
558
559 PAGED_CODE();
560
561 //
562 // Build the lookaside list for srb's for the physical disk. Should only
563 // need a couple.
564 //
565
566 ClassInitializeSrbLookasideList(&(fdoExtension->CommonExtension),
567 CDROM_SRB_LIST_SIZE);
568
569 //
570 // Allocate request sense buffer.
571 //
572
573 senseData = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
574 SENSE_BUFFER_SIZE,
575 CDROM_TAG_SENSE_INFO);
576
577 if (senseData == NULL) {
578
579 //
580 // The buffer cannot be allocated.
581 //
582
583 status = STATUS_INSUFFICIENT_RESOURCES;
584 goto CdRomInitDeviceExit;
585 }
586
587 //
588 // Set the sense data pointer in the device extension.
589 //
590
591 fdoExtension->SenseData = senseData;
592
593 //
594 // CDROMs are not partitionable so starting offset is 0.
595 //
596
597 commonExtension->StartingOffset.LowPart = 0;
598 commonExtension->StartingOffset.HighPart = 0;
599
600 //
601 // Set timeout value in seconds.
602 //
603
604 timeOut = ClassQueryTimeOutRegistryValue(Fdo);
605 if (timeOut) {
606 fdoExtension->TimeOutValue = timeOut;
607 } else {
608 fdoExtension->TimeOutValue = SCSI_CDROM_TIMEOUT;
609 }
610
611 cddata = (PCDROM_DATA)(commonExtension->DriverData);
612
613 //
614 // Set up media change support defaults.
615 //
616
617 KeInitializeSpinLock(&cddata->DelayedRetrySpinLock);
618
619 cddata->DelayedRetryIrp = NULL;
620 cddata->DelayedRetryInterval = 0;
621 cddata->Mmc.WriteAllowed = FALSE;
622
623 //
624 // Scan for controllers that require special processing.
625 //
626
627 ScanForSpecial(Fdo);
628
629 //
630 // Determine if the drive is MMC-Capable
631 //
632
633 CdRomIsDeviceMmcDevice(Fdo, &isMmcDevice);
634
635 if (!isMmcDevice) {
636
637 SET_FLAG(Fdo->Characteristics, FILE_READ_ONLY_DEVICE);
638
639 } else {
640
641 //
642 // the drive supports at least a subset of MMC commands
643 // (and therefore supports READ_CD, etc...)
644 //
645
646 cddata->Mmc.IsMmc = TRUE;
647
648 //
649 // allocate a buffer for all the capabilities and such
650 //
651
652 status = CdRomAllocateMmcResources(Fdo);
653 if (!NT_SUCCESS(status)) {
654 goto CdRomInitDeviceExit;
655 }
656
657
658 #if 0
659 //
660 // determine all the various media types from the profiles feature
661 //
662 {
663 PFEATURE_DATA_PROFILE_LIST profileHeader;
664 ULONG mediaTypes = 0;
665 ULONG i;
666
667 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugError,
668 "Checking all profiles for media types supported.\n"
669 ));
670
671 profileHeader = CdRomFindFeaturePage(cddata->Mmc.CapabilitiesBuffer,
672 cddata->Mmc.CapabilitiesBufferSize,
673 FeatureProfileList);
674 if (profileHeader == NULL) {
675
676 //
677 // if profiles don't exist, there is something seriously
678 // wrong with this command -- it's either not a cdrom or
679 // one that hasn't implemented the spec correctly. exit
680 // now while we have the chance to do so safely.
681 //
682 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugError,
683 "CdromDevice supports GET_CONFIGURATION, but "
684 "doesn't provide profiles for PDO %p!\n",
685 fdoExtension->LowerPdo));
686 status = STATUS_DEVICE_CONFIGURATION_ERROR;
687 goto CdRomInitDeviceExit;
688
689 }
690
691 for (i = 0; i < MAX_CDROM_MEDIA_TYPES; i++) {
692
693 BOOLEAN profileFound;
694 CdRomFindProfileInProfiles(profileHeader,
695 MediaProfileMatch[i].Profile,
696 &profileFound);
697 if (profileFound) {
698
699 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugError,
700 "CdromInit -> Found Profile %x => Media %x "
701 "(%x total)\n",
702 MediaProfileMatch[i].Profile,
703 MediaProfileMatch[i].Media,
704 mediaTypes + 1
705 ));
706
707 cddata->Mmc.MediaProfileMatches[mediaTypes] =
708 MediaProfileMatch[i];
709 mediaTypes++;
710
711 }
712
713 }
714
715 if (mediaTypes == 0) {
716
717 //
718 // if profiles don't exist, there is something seriously
719 // wrong with this command -- it's either not a cdrom or
720 // one that hasn't implemented the spec correctly. exit
721 // now while we have the chance to do so safely.
722 //
723 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugError,
724 "CdromDevice supports GET_CONFIGURATION, but "
725 "doesn't support any of the standard profiles "
726 "for PDO %p!\n", fdoExtension->LowerPdo));
727 status = STATUS_DEVICE_CONFIGURATION_ERROR;
728 goto CdRomInitDeviceExit;
729
730 }
731
732 cddata->Mmc.MediaTypes = mediaTypes;
733
734
735 }
736 #endif // media checks, and all failure paths due to bad firmware.
737
738 //
739 // if the drive supports target defect management and sector-addressable
740 // writes, then we should allow writes to the media.
741 //
742
743 if (CdRomFindFeaturePage(cddata->Mmc.CapabilitiesBuffer,
744 cddata->Mmc.CapabilitiesBufferSize,
745 FeatureDefectManagement) &&
746 CdRomFindFeaturePage(cddata->Mmc.CapabilitiesBuffer,
747 cddata->Mmc.CapabilitiesBufferSize,
748 FeatureRandomWritable)) {
749
750 //
751 // the drive is target defect managed, and supports random writes
752 // on sector-alignment. allow writes to occur by setting the error
753 // handler to point to a private media change detection handler.
754 //
755
756 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
757 "Found a WRITE capable device: %p\n", Fdo));
758
759 //
760 // the write specific pages have been found --
761 // set the error handler and set it to require an update!
762 //
763
764 cddata->Mmc.UpdateState = CdromMmcUpdateRequired;
765 cddata->ErrorHandler = CdRomMmcErrorHandler;
766
767 }
768
769 //
770 // ISSUE-2000/4/4-henrygab - mmc-compliant compliant drives should
771 // be initialized based upon reported
772 // capabilities, such as CSS, Analogue Audio,
773 // READ_CD capabilities, and (possibly) even
774 // drive capacity information.
775 //
776
777 TraceLog((CdromDebugWarning,
778 "Defaulting to READ_CD because device %p is MMC compliant\n",
779 Fdo));
780 SET_FLAG(fdoExtension->DeviceFlags, DEV_SAFE_START_UNIT);
781 SET_FLAG(cddata->XAFlags, XA_USE_READ_CD);
782
783 }
784
785
786 //
787 // Set the default geometry for the cdrom to match what NT 4 used.
788 // Classpnp will use these values to compute the cylinder count rather
789 // than using it's NT 5.0 defaults.
790 //
791
792 fdoExtension->DiskGeometry.TracksPerCylinder = 0x40;
793 fdoExtension->DiskGeometry.SectorsPerTrack = 0x20;
794
795 //
796 // Do READ CAPACITY. This SCSI command returns the last sector address
797 // on the device and the bytes per sector. These are used to calculate
798 // the drive capacity in bytes.
799 //
800 // NOTE: This should be change to send the Srb synchronously, then
801 // call CdRomInterpretReadCapacity() to properly setup the defaults.
802 //
803
804 status = ClassReadDriveCapacity(Fdo);
805
806 bps = fdoExtension->DiskGeometry.BytesPerSector;
807
808 if (!NT_SUCCESS(status) || !bps) {
809
810 TraceLog((CdromDebugWarning,
811 "CdRomStartDevice: Can't read capacity for device %wZ\n",
812 &(fdoExtension->CommonExtension.DeviceName)));
813
814 //
815 // Set disk geometry to default values (per ISO 9660).
816 //
817
818 bps = 2048;
819 fdoExtension->SectorShift = 11;
820 commonExtension->PartitionLength.QuadPart = (LONGLONG)(0x7fffffff);
821
822 } else {
823
824 //
825 // Insure that bytes per sector is a power of 2
826 // This corrects a problem with the HP 4020i CDR where it
827 // returns an incorrect number for bytes per sector.
828 //
829
830 lastBit = (ULONG) -1;
831 while (bps) {
832 lastBit++;
833 bps = bps >> 1;
834 }
835
836 bps = 1 << lastBit;
837 }
838 fdoExtension->DiskGeometry.BytesPerSector = bps;
839 TraceLog((CdromDebugTrace, "CdRomInitDevice: Calc'd bps = %x\n", bps));
840
841
842 ClassInitializeMediaChangeDetection(fdoExtension, "CdRom");
843
844
845 //
846 // test for audio read capabilities
847 //
848
849 TraceLog((CdromDebugWarning,
850 "Detecting XA_READ capabilities\n"));
851
852 if (CdRomGetDeviceType(Fdo) == FILE_DEVICE_DVD) {
853
854 TraceLog((CdromDebugWarning,
855 "CdRomInitDevice: DVD Devices require START_UNIT\n"));
856
857
858 //
859 // all DVD devices must support the READ_CD command
860 //
861
862 TraceLog((CdromDebugWarning,
863 "CdRomDetermineRawReadCapabilities: DVD devices "
864 "support READ_CD command for FDO %p\n", Fdo));
865 SET_FLAG(fdoExtension->DeviceFlags, DEV_SAFE_START_UNIT);
866 SET_FLAG(cddata->XAFlags, XA_USE_READ_CD);
867
868
869 status = STATUS_SUCCESS;
870
871 } else if ((fdoExtension->DeviceDescriptor->BusType != BusTypeScsi) &&
872 (fdoExtension->DeviceDescriptor->BusType != BusTypeAta) &&
873 (fdoExtension->DeviceDescriptor->BusType != BusTypeAtapi) &&
874 (fdoExtension->DeviceDescriptor->BusType != BusTypeUnknown)
875 ) {
876
877 //
878 // devices on the newer busses must support READ_CD command
879 //
880
881 TraceLog((CdromDebugWarning,
882 "CdRomDetermineRawReadCapabilities: Devices for newer "
883 "busses must support READ_CD command for FDO %p, Bus %x\n",
884 Fdo, fdoExtension->DeviceDescriptor->BusType));
885 SET_FLAG(fdoExtension->DeviceFlags, DEV_SAFE_START_UNIT);
886 SET_FLAG(cddata->XAFlags, XA_USE_READ_CD);
887
888 }
889
890 //
891 // now clear all our READ_CD flags if the drive should have supported
892 // it, but we are not sure it actually does. we still won't query
893 // the drive more than one time if it supports the command.
894 //
895
896 if (TEST_FLAG(cddata->HackFlags, CDROM_HACK_FORCE_READ_CD_DETECTION)) {
897
898 TraceLog((CdromDebugWarning,
899 "Forcing detection of READ_CD for FDO %p because "
900 "testing showed some firmware did not properly support it\n",
901 Fdo));
902 CLEAR_FLAG(cddata->XAFlags, XA_USE_READ_CD);
903
904 }
905
906
907 //
908 // read our READ_CD support in the registry if it was seeded.
909 //
910 {
911 ULONG readCdSupported = 0;
912
913 ClassGetDeviceParameter(fdoExtension,
914 CDROM_SUBKEY_NAME,
915 CDROM_READ_CD_NAME,
916 &readCdSupported
917 );
918
919 if (readCdSupported != 0) {
920
921 TraceLog((CdromDebugWarning,
922 "Defaulting to READ_CD because previously detected "
923 "that the device supports it for Fdo %p.\n",
924 Fdo
925 ));
926 SET_FLAG(cddata->XAFlags, XA_USE_READ_CD);
927
928 }
929
930 }
931
932
933 //
934 // backwards-compatible hackish attempt to determine if the drive
935 // supports any method of reading digital audio from the disc.
936 //
937
938 if (!TEST_FLAG(cddata->XAFlags, XA_USE_READ_CD)) {
939
940 SCSI_REQUEST_BLOCK srb;
941 PCDB cdb;
942 ULONG length;
943 PUCHAR buffer = NULL;
944 ULONG count;
945
946 //
947 // ISSUE-2000/07/05-henrygab - use the mode page to determine
948 // READ_CD support, then fall back on the below
949 // (unreliable?) hack.
950 //
951
952 //
953 // Build the MODE SENSE CDB. The data returned will be kept in the
954 // device extension and used to set block size.
955 //
956
957 length = max(sizeof(ERROR_RECOVERY_DATA),sizeof(ERROR_RECOVERY_DATA10));
958
959 buffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
960 length,
961 CDROM_TAG_MODE_DATA);
962
963 if (!buffer) {
964 TraceLog((CdromDebugWarning,
965 "CdRomDetermineRawReadCapabilities: cannot allocate "
966 "buffer, so leaving for FDO %p\n", Fdo));
967 status = STATUS_INSUFFICIENT_RESOURCES;
968 goto CdRomInitDeviceExit;
969 }
970
971 for (count = 0; count < 2; count++) {
972
973 if (count == 0) {
974 length = sizeof(ERROR_RECOVERY_DATA);
975 } else {
976 length = sizeof(ERROR_RECOVERY_DATA10);
977 }
978
979 RtlZeroMemory(buffer, length);
980 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
981 cdb = (PCDB)srb.Cdb;
982
983 srb.TimeOutValue = fdoExtension->TimeOutValue;
984
985 if (count == 0) {
986 srb.CdbLength = 6;
987 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
988 cdb->MODE_SENSE.PageCode = 0x1;
989 // note: not setting DBD in order to get the block descriptor!
990 cdb->MODE_SENSE.AllocationLength = (UCHAR)length;
991 } else {
992 srb.CdbLength = 10;
993 cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
994 cdb->MODE_SENSE10.PageCode = 0x1;
995 // note: not setting DBD in order to get the block descriptor!
996 cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(length >> 8);
997 cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(length & 0xFF);
998 }
999
1000 status = ClassSendSrbSynchronous(Fdo,
1001 &srb,
1002 buffer,
1003 length,
1004 FALSE);
1005
1006
1007 if (NT_SUCCESS(status) || (status == STATUS_DATA_OVERRUN)) {
1008
1009 //
1010 // STATUS_DATA_OVERRUN means it's a newer drive with more info
1011 // to tell us, so it's probably able to support READ_CD
1012 //
1013
1014 RtlZeroMemory(cdb, CDB12GENERIC_LENGTH);
1015
1016 srb.CdbLength = 12;
1017 cdb->READ_CD.OperationCode = SCSIOP_READ_CD;
1018
1019 status = ClassSendSrbSynchronous(Fdo,
1020 &srb,
1021 NULL,
1022 0,
1023 FALSE);
1024
1025 if (NT_SUCCESS(status) ||
1026 (status == STATUS_NO_MEDIA_IN_DEVICE) ||
1027 (status == STATUS_NONEXISTENT_SECTOR) ||
1028 (status == STATUS_UNRECOGNIZED_MEDIA)
1029 ) {
1030
1031 //
1032 // READ_CD works
1033 //
1034
1035 TraceLog((CdromDebugWarning,
1036 "CdRomDetermineRawReadCapabilities: Using "
1037 "READ_CD for FDO %p due to status %x\n",
1038 Fdo,
1039 status));
1040 SET_FLAG(cddata->XAFlags, XA_USE_READ_CD);
1041
1042 //
1043 // ignore errors in saving this info
1044 //
1045
1046 ClassSetDeviceParameter(fdoExtension,
1047 CDROM_SUBKEY_NAME,
1048 CDROM_READ_CD_NAME,
1049 1
1050 );
1051
1052
1053 break; // out of the for loop
1054
1055 }
1056
1057 TraceLog((CdromDebugWarning,
1058 "CdRomDetermineRawReadCapabilities: Using "
1059 "%s-byte mode switching for FDO %p due to status "
1060 "%x returned for READ_CD\n",
1061 ((count == 0) ? "6" : "10"), Fdo, status));
1062
1063 if (count == 0) {
1064 SET_FLAG(cddata->XAFlags, XA_USE_6_BYTE);
1065 RtlCopyMemory(&cddata->Header,
1066 buffer,
1067 sizeof(ERROR_RECOVERY_DATA));
1068 cddata->Header.ModeDataLength = 0;
1069 } else {
1070 SET_FLAG(cddata->XAFlags, XA_USE_10_BYTE);
1071 RtlCopyMemory(&cddata->Header10,
1072 buffer,
1073 sizeof(ERROR_RECOVERY_DATA10));
1074 cddata->Header10.ModeDataLength[0] = 0;
1075 cddata->Header10.ModeDataLength[1] = 0;
1076 }
1077 break; // out of for loop
1078
1079 }
1080 TraceLog((CdromDebugWarning,
1081 "FDO %p failed %x byte mode sense, status %x\n",
1082 Fdo,
1083 ((count == 0) ? 6 : 10),
1084 status
1085 ));
1086
1087 //
1088 // mode sense failed
1089 //
1090
1091 } // end of for loop to try 6 and 10-byte mode sense
1092
1093 if (count == 2) {
1094
1095 //
1096 // nothing worked. we probably cannot support digital
1097 // audio extraction from this drive
1098 //
1099
1100 TraceLog((CdromDebugWarning,
1101 "CdRomDetermineRawReadCapabilities: FDO %p "
1102 "cannot support READ_CD\n", Fdo));
1103 CLEAR_FLAG(cddata->XAFlags, XA_PLEXTOR_CDDA);
1104 CLEAR_FLAG(cddata->XAFlags, XA_NEC_CDDA);
1105 SET_FLAG(cddata->XAFlags, XA_NOT_SUPPORTED);
1106
1107 } // end of count == 2
1108
1109 //
1110 // free our resources
1111 //
1112
1113 ExFreePool(buffer);
1114
1115 //
1116 // set a successful status
1117 // (in case someone later checks this)
1118 //
1119
1120 status = STATUS_SUCCESS;
1121
1122 }
1123
1124 //
1125 // Register interfaces for this device.
1126 //
1127
1128 {
1129 UNICODE_STRING interfaceName;
1130
1131 RtlInitUnicodeString(&interfaceName, NULL);
1132
1133 status = IoRegisterDeviceInterface(fdoExtension->LowerPdo,
1134 (LPGUID) &CdRomClassGuid,
1135 NULL,
1136 &interfaceName);
1137
1138 if(NT_SUCCESS(status)) {
1139
1140 cddata->CdromInterfaceString = interfaceName;
1141
1142 status = IoSetDeviceInterfaceState(
1143 &interfaceName,
1144 TRUE);
1145
1146 if(!NT_SUCCESS(status)) {
1147
1148 TraceLog((CdromDebugWarning,
1149 "CdromInitDevice: Unable to register cdrom "
1150 "DCA for fdo %p [%lx]\n",
1151 Fdo, status));
1152 }
1153 }
1154 }
1155
1156 return(STATUS_SUCCESS);
1157
1158 CdRomInitDeviceExit:
1159
1160 CdRomDeAllocateMmcResources(Fdo);
1161 RtlZeroMemory(&(cddata->Mmc), sizeof(CDROM_MMC_EXTENSION));
1162
1163 return status;
1164
1165 }
1166
1167 NTSTATUS
1168 NTAPI
1169 CdRomStartDevice(
1170 IN PDEVICE_OBJECT Fdo
1171 )
1172 /*++
1173
1174 Routine Description:
1175
1176 This routine starts the timer for the cdrom
1177
1178 Arguments:
1179
1180 Fdo - a pointer to the functional device object for this device
1181
1182 Return Value:
1183
1184 status
1185
1186 --*/
1187
1188 {
1189 PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
1190 PCDROM_DATA cddata = (PCDROM_DATA)(commonExtension->DriverData);
1191 PDVD_COPY_PROTECT_KEY copyProtectKey;
1192 PDVD_RPC_KEY rpcKey;
1193 IO_STATUS_BLOCK ioStatus;
1194 ULONG bufferLen;
1195
1196 // CdRomCreateWellKnownName(Fdo);
1197
1198 //
1199 // if we have a DVD-ROM
1200 // if we have a rpc0 device
1201 // fake a rpc2 device
1202 // if device does not have a dvd region set
1203 // select a dvd region for the user
1204 //
1205
1206 cddata->DvdRpc0Device = FALSE;
1207
1208 //
1209 // since StartIo() will call IoStartNextPacket() on error, allowing
1210 // StartIo() to be non-recursive prevents stack overflow bugchecks in
1211 // severe error cases (such as fault-injection in the verifier).
1212 //
1213 // the only difference is that the thread context may be different
1214 // in StartIo() than in the caller of IoStartNextPacket().
1215 //
1216
1217 IoSetStartIoAttributes(Fdo, TRUE, TRUE);
1218
1219 //
1220 // check to see if we have a DVD device
1221 //
1222
1223 if (CdRomGetDeviceType(Fdo) != FILE_DEVICE_DVD) {
1224 return STATUS_SUCCESS;
1225 }
1226
1227 //
1228 // we got a DVD drive.
1229 // now, figure out if we have a RPC0 device
1230 //
1231
1232 bufferLen = DVD_RPC_KEY_LENGTH;
1233 copyProtectKey =
1234 (PDVD_COPY_PROTECT_KEY)ExAllocatePoolWithTag(PagedPool,
1235 bufferLen,
1236 DVD_TAG_RPC2_CHECK);
1237
1238 if (copyProtectKey == NULL) {
1239 return STATUS_INSUFFICIENT_RESOURCES;
1240 }
1241
1242 //
1243 // get the device region
1244 //
1245 RtlZeroMemory (copyProtectKey, bufferLen);
1246 copyProtectKey->KeyLength = DVD_RPC_KEY_LENGTH;
1247 copyProtectKey->KeyType = DvdGetRpcKey;
1248
1249 //
1250 // Build a request for READ_KEY
1251 //
1252 ClassSendDeviceIoControlSynchronous(
1253 IOCTL_DVD_READ_KEY,
1254 Fdo,
1255 copyProtectKey,
1256 DVD_RPC_KEY_LENGTH,
1257 DVD_RPC_KEY_LENGTH,
1258 FALSE,
1259 &ioStatus
1260 );
1261
1262 if (!NT_SUCCESS(ioStatus.Status)) {
1263
1264 //
1265 // we have a rpc0 device
1266 //
1267 // NOTE: THIS MODIFIES THE BEHAVIOR OF THE IOCTL
1268 //
1269
1270 cddata->DvdRpc0Device = TRUE;
1271
1272 TraceLog((CdromDebugWarning,
1273 "CdromStartDevice (%p): RPC Phase 1 drive detected\n",
1274 Fdo));
1275
1276 //
1277 // note: we could force this chosen now, but it's better to reduce
1278 // the number of code paths that could be taken. always delay to
1279 // increase the percentage code coverage.
1280 //
1281
1282 TraceLog((CdromDebugWarning,
1283 "CdromStartDevice (%p): Delay DVD Region Selection\n",
1284 Fdo));
1285
1286 cddata->Rpc0SystemRegion = 0xff;
1287 cddata->Rpc0SystemRegionResetCount = DVD_MAX_REGION_RESET_COUNT;
1288 cddata->PickDvdRegion = 1;
1289 cddata->Rpc0RetryRegistryCallback = 1;
1290 ExFreePool(copyProtectKey);
1291 return STATUS_SUCCESS;
1292
1293 } else {
1294
1295 rpcKey = (PDVD_RPC_KEY) copyProtectKey->KeyData;
1296
1297 //
1298 // TypeCode of zero means that no region has been set.
1299 //
1300
1301 if (rpcKey->TypeCode == 0) {
1302 TraceLog((CdromDebugWarning,
1303 "CdromStartDevice (%p): must choose DVD region\n",
1304 Fdo));
1305 cddata->PickDvdRegion = 1;
1306 CdRomPickDvdRegion(Fdo);
1307 }
1308 }
1309
1310 ExFreePool (copyProtectKey);
1311
1312 return STATUS_SUCCESS;
1313 }
1314
1315 NTSTATUS
1316 NTAPI
1317 CdRomStopDevice(
1318 IN PDEVICE_OBJECT DeviceObject,
1319 IN UCHAR Type
1320 )
1321 {
1322 return STATUS_SUCCESS;
1323 }
1324
1325 VOID
1326 NTAPI
1327 CdRomStartIo(
1328 IN PDEVICE_OBJECT Fdo,
1329 IN PIRP Irp
1330 )
1331 {
1332
1333 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
1334 PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
1335
1336 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
1337 PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
1338 PIO_STACK_LOCATION irpStack;
1339
1340 PIRP irp2 = NULL;
1341
1342 ULONG transferPages;
1343 ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
1344 //LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
1345 PCDROM_DATA cdData;
1346 PSCSI_REQUEST_BLOCK srb = NULL;
1347 PCDB cdb;
1348 PUCHAR senseBuffer = NULL;
1349 PVOID dataBuffer;
1350 NTSTATUS status;
1351 BOOLEAN use6Byte;
1352
1353 //
1354 // Mark IRP with status pending.
1355 //
1356
1357 IoMarkIrpPending(Irp);
1358
1359 cdData = (PCDROM_DATA)(fdoExtension->CommonExtension.DriverData);
1360 use6Byte = TEST_FLAG(cdData->XAFlags, XA_USE_6_BYTE);
1361
1362 //
1363 // if this test is true, then we will exit the routine within this
1364 // code block, queueing the irp for later completion.
1365 //
1366
1367 if ((cdData->Mmc.IsMmc) &&
1368 (cdData->Mmc.UpdateState != CdromMmcUpdateComplete)
1369 ) {
1370
1371 USHORT queueDepth;
1372 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
1373 "CdRomStartIo: [%p] Device needs to update capabilities\n",
1374 Irp));
1375 ASSERT(cdData->Mmc.IsMmc);
1376 ASSERT(cdData->Mmc.CapabilitiesIrp != NULL);
1377 ASSERT(cdData->Mmc.CapabilitiesIrp != Irp);
1378
1379 //
1380 // NOTE - REF #0002
1381 //
1382 // the state was either UpdateRequired (which means we will
1383 // have to start the work item) or UpdateStarted (which means
1384 // we have already started the work item at least once -- may
1385 // transparently change to UpdateComplete).
1386 //
1387 // if it's update required, we just queue it, change to UpdateStarted,
1388 // start the workitem, and start the next packet.
1389 //
1390 // else, we must queue the item and check the queue depth. if the
1391 // queue depth is equal to 1, that means the worker item from the
1392 // previous attempt has already de-queued the items, so we should
1393 // call this routine again (retry) as an optimization rather than
1394 // re-add it this irp to the queue. since this is tail recursion,
1395 // it won't take much/any stack to do this.
1396 //
1397 // NOTE: This presumes the following items are true:
1398 //
1399 // we only add to the list from CdRomStartIo(), which is serialized.
1400 // we only set to UpdateStarted from CdRomStartIo(), and only if
1401 // the state was UpdateRequired.
1402 // we only set to UpdateRequired from CdRomMmcErrorHandler(), and
1403 // only if the state was UpdateComplete.
1404 // we only set to UpdateComplete from the workitem, and assert the
1405 // state was UpdateStarted.
1406 // we flush the entire queue in one atomic operation in the workitem,
1407 // except in the special case described above when we dequeue
1408 // the request immediately.
1409 //
1410 // order of operations is vitally important: queue, then test the depth
1411 // this will prevent lost irps.
1412 //
1413
1414 ExInterlockedPushEntrySList(&(cdData->Mmc.DelayedIrps),
1415 (PSINGLE_LIST_ENTRY)&(Irp->Tail.Overlay.DriverContext[0]),
1416 &(cdData->Mmc.DelayedLock));
1417
1418 queueDepth = ExQueryDepthSList(&(cdData->Mmc.DelayedIrps));
1419 if (queueDepth == 1) {
1420
1421 if (cdData->Mmc.UpdateState == CdromMmcUpdateRequired) {
1422 LONG oldState;
1423
1424 //
1425 // should free any old partition list info that
1426 // we've previously saved away and then start the WorkItem
1427 //
1428
1429 oldState = InterlockedExchange(&cdData->Mmc.UpdateState,
1430 CdromMmcUpdateStarted);
1431 ASSERT(oldState == CdromMmcUpdateRequired);
1432
1433 IoQueueWorkItem(cdData->Mmc.CapabilitiesWorkItem,
1434 CdRomUpdateMmcDriveCapabilities,
1435 DelayedWorkQueue,
1436 NULL);
1437
1438 } else {
1439
1440 //
1441 // they *just* finished updating, so we should flush the list
1442 // back onto the StartIo queue and start the next packet.
1443 //
1444
1445 CdRompFlushDelayedList(Fdo, &(cdData->Mmc), STATUS_SUCCESS, FALSE);
1446
1447 }
1448
1449 }
1450
1451 //
1452 // start the next packet so we don't deadlock....
1453 //
1454
1455 IoStartNextPacket(Fdo, FALSE);
1456 return;
1457
1458 }
1459
1460 //
1461 // If the flag is set in the device object
1462 // force a verify for READ, WRITE and RAW_READ requests
1463 // Note that ioctls are passed through....
1464 //
1465
1466 if (TEST_FLAG(Fdo->Flags, DO_VERIFY_VOLUME) &&
1467 IS_READ_WRITE_REQUEST(currentIrpStack)) {
1468
1469 TraceLog((CdromDebugTrace,
1470 "CdRomStartIo: [%p] Volume needs verified\n", Irp));
1471
1472 if (!(currentIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME)) {
1473
1474 if (Irp->Tail.Overlay.Thread) {
1475 IoSetHardErrorOrVerifyDevice(Irp, Fdo);
1476 }
1477
1478 Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
1479
1480 TraceLog((CdromDebugTrace,
1481 "CdRomStartIo: [%p] Calling UpdateCapacity - "
1482 "ioctl event = %p\n",
1483 Irp,
1484 nextIrpStack->Parameters.Others.Argument1
1485 ));
1486
1487 //
1488 // our device control dispatch routine stores an event in the next
1489 // stack location to signal when startio has completed. We need to
1490 // pass this in so that the update capacity completion routine can
1491 // set it rather than completing the Irp.
1492 //
1493
1494 status = CdRomUpdateCapacity(fdoExtension,
1495 Irp,
1496 nextIrpStack->Parameters.Others.Argument1
1497 );
1498
1499 TraceLog((CdromDebugTrace,
1500 "CdRomStartIo: [%p] UpdateCapacity returned %lx\n",
1501 Irp, status));
1502 return;
1503 }
1504 }
1505
1506 //
1507 // fail writes if they are not allowed...
1508 //
1509
1510 if ((currentIrpStack->MajorFunction == IRP_MJ_WRITE) &&
1511 !(cdData->Mmc.WriteAllowed)) {
1512
1513 TraceLog((CdromDebugError,
1514 "CdRomStartIo: [%p] Device %p failing write request\n",
1515 Irp, Fdo));
1516
1517 Irp->IoStatus.Information = 0;
1518 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
1519 BAIL_OUT(Irp);
1520 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
1521 return;
1522 }
1523
1524 if (currentIrpStack->MajorFunction == IRP_MJ_READ ||
1525 currentIrpStack->MajorFunction == IRP_MJ_WRITE ) {
1526
1527 ULONG maximumTransferLength = fdoExtension->AdapterDescriptor->MaximumTransferLength;
1528
1529 //
1530 // Add partition byte offset to make starting byte relative to
1531 // beginning of disk.
1532 //
1533
1534 currentIrpStack->Parameters.Read.ByteOffset.QuadPart +=
1535 (fdoExtension->CommonExtension.StartingOffset.QuadPart);
1536
1537 //
1538 // Calculate number of pages in this transfer.
1539 //
1540
1541 transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress),
1542 currentIrpStack->Parameters.Read.Length);
1543
1544 //
1545 // Check if request length is greater than the maximum number of
1546 // bytes that the hardware can transfer.
1547 //
1548
1549 if (cdData->RawAccess) {
1550
1551 //
1552 // a writable device must be MMC compliant, which supports
1553 // READ_CD commands.
1554 //
1555
1556 ASSERT(currentIrpStack->MajorFunction != IRP_MJ_WRITE);
1557
1558 ASSERT(!TEST_FLAG(cdData->XAFlags, XA_USE_READ_CD));
1559
1560 //
1561 // Fire off a mode select to switch back to cooked sectors.
1562 //
1563
1564 irp2 = IoAllocateIrp((CCHAR)(Fdo->StackSize+1), FALSE);
1565
1566 if (!irp2) {
1567 Irp->IoStatus.Information = 0;
1568 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1569
1570 BAIL_OUT(Irp);
1571 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
1572 return;
1573 }
1574
1575 srb = ExAllocatePoolWithTag(NonPagedPool,
1576 sizeof(SCSI_REQUEST_BLOCK),
1577 CDROM_TAG_SRB);
1578 if (!srb) {
1579 IoFreeIrp(irp2);
1580 Irp->IoStatus.Information = 0;
1581 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1582
1583 BAIL_OUT(Irp);
1584 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
1585 return;
1586 }
1587
1588 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
1589
1590 cdb = (PCDB)srb->Cdb;
1591
1592 //
1593 // Allocate sense buffer.
1594 //
1595
1596 senseBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
1597 SENSE_BUFFER_SIZE,
1598 CDROM_TAG_SENSE_INFO);
1599
1600 if (!senseBuffer) {
1601 ExFreePool(srb);
1602 IoFreeIrp(irp2);
1603 Irp->IoStatus.Information = 0;
1604 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1605
1606 BAIL_OUT(Irp);
1607 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
1608 return;
1609 }
1610
1611 //
1612 // Set up the irp.
1613 //
1614
1615 IoSetNextIrpStackLocation(irp2);
1616 irp2->IoStatus.Status = STATUS_SUCCESS;
1617 irp2->IoStatus.Information = 0;
1618 irp2->Flags = 0;
1619 irp2->UserBuffer = NULL;
1620
1621 //
1622 // Save the device object and irp in a private stack location.
1623 //
1624
1625 irpStack = IoGetCurrentIrpStackLocation(irp2);
1626 irpStack->DeviceObject = Fdo;
1627 irpStack->Parameters.Others.Argument2 = (PVOID) Irp;
1628
1629 //
1630 // The retry count will be in the real Irp, as the retry logic will
1631 // recreate our private irp.
1632 //
1633
1634 if (!(nextIrpStack->Parameters.Others.Argument1)) {
1635
1636 //
1637 // Only jam this in if it doesn't exist. The completion routines can
1638 // call StartIo directly in the case of retries and resetting it will
1639 // cause infinite loops.
1640 //
1641
1642 nextIrpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
1643 }
1644
1645 //
1646 // Construct the IRP stack for the lower level driver.
1647 //
1648
1649 irpStack = IoGetNextIrpStackLocation(irp2);
1650 irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
1651 irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
1652 irpStack->Parameters.Scsi.Srb = srb;
1653
1654 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
1655 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1656 srb->SrbStatus = srb->ScsiStatus = 0;
1657 srb->NextSrb = 0;
1658 srb->OriginalRequest = irp2;
1659 srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
1660 srb->SenseInfoBuffer = senseBuffer;
1661
1662 transferByteCount = (use6Byte) ? sizeof(ERROR_RECOVERY_DATA) : sizeof(ERROR_RECOVERY_DATA10);
1663
1664 dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
1665 transferByteCount,
1666 CDROM_TAG_RAW);
1667
1668 if (!dataBuffer) {
1669 ExFreePool(senseBuffer);
1670 ExFreePool(srb);
1671 IoFreeIrp(irp2);
1672 Irp->IoStatus.Information = 0;
1673 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1674
1675 BAIL_OUT(Irp);
1676 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
1677 return;
1678
1679 }
1680
1681 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
1682 transferByteCount,
1683 FALSE,
1684 FALSE,
1685 (PIRP) NULL);
1686
1687 if (!irp2->MdlAddress) {
1688 ExFreePool(senseBuffer);
1689 ExFreePool(srb);
1690 ExFreePool(dataBuffer);
1691 IoFreeIrp(irp2);
1692 Irp->IoStatus.Information = 0;
1693 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1694
1695 BAIL_OUT(Irp);
1696 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
1697 return;
1698 }
1699
1700 //
1701 // Prepare the MDL
1702 //
1703
1704 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
1705
1706 srb->DataBuffer = dataBuffer;
1707
1708 //
1709 // Set the new block size in the descriptor.
1710 //
1711
1712 if (use6Byte) {
1713 cdData->BlockDescriptor.BlockLength[0] = (UCHAR)(COOKED_SECTOR_SIZE >> 16) & 0xFF;
1714 cdData->BlockDescriptor.BlockLength[1] = (UCHAR)(COOKED_SECTOR_SIZE >> 8) & 0xFF;
1715 cdData->BlockDescriptor.BlockLength[2] = (UCHAR)(COOKED_SECTOR_SIZE & 0xFF);
1716 } else {
1717 cdData->BlockDescriptor10.BlockLength[0] = (UCHAR)(COOKED_SECTOR_SIZE >> 16) & 0xFF;
1718 cdData->BlockDescriptor10.BlockLength[1] = (UCHAR)(COOKED_SECTOR_SIZE >> 8) & 0xFF;
1719 cdData->BlockDescriptor10.BlockLength[2] = (UCHAR)(COOKED_SECTOR_SIZE & 0xFF);
1720 }
1721
1722 //
1723 // Move error page into dataBuffer.
1724 //
1725
1726 RtlCopyMemory(srb->DataBuffer, &cdData->Header, transferByteCount);
1727
1728 //
1729 // Build and send a mode select to switch into raw mode.
1730 //
1731
1732 srb->SrbFlags = fdoExtension->SrbFlags;
1733 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
1734 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_OUT);
1735 srb->DataTransferLength = transferByteCount;
1736 srb->TimeOutValue = fdoExtension->TimeOutValue * 2;
1737
1738 if (use6Byte) {
1739 srb->CdbLength = 6;
1740 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
1741 cdb->MODE_SELECT.PFBit = 1;
1742 cdb->MODE_SELECT.ParameterListLength = (UCHAR)transferByteCount;
1743 } else {
1744 srb->CdbLength = 10;
1745 cdb->MODE_SELECT10.OperationCode = SCSIOP_MODE_SELECT10;
1746 cdb->MODE_SELECT10.PFBit = 1;
1747 cdb->MODE_SELECT10.ParameterListLength[0] = (UCHAR)(transferByteCount >> 8);
1748 cdb->MODE_SELECT10.ParameterListLength[1] = (UCHAR)(transferByteCount & 0xFF);
1749 }
1750
1751 //
1752 // Update completion routine.
1753 //
1754
1755 IoSetCompletionRoutine(irp2,
1756 CdRomSwitchModeCompletion,
1757 srb,
1758 TRUE,
1759 TRUE,
1760 TRUE);
1761
1762 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
1763 return;
1764 }
1765
1766
1767 //
1768 // Request needs to be split. Completion of each portion of the
1769 // request will fire off the next portion. The final request will
1770 // signal Io to send a new request.
1771 //
1772
1773 transferPages =
1774 fdoExtension->AdapterDescriptor->MaximumPhysicalPages - 1;
1775
1776 if(maximumTransferLength > (transferPages << PAGE_SHIFT)) {
1777 maximumTransferLength = transferPages << PAGE_SHIFT;
1778 }
1779
1780 //
1781 // Check that the maximum transfer size is not zero
1782 //
1783
1784 if(maximumTransferLength == 0) {
1785 maximumTransferLength = PAGE_SIZE;
1786 }
1787
1788 ClassSplitRequest(Fdo, Irp, maximumTransferLength);
1789 return;
1790
1791 } else if (currentIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
1792
1793 //
1794 // Allocate an irp, srb and associated structures.
1795 //
1796
1797 irp2 = IoAllocateIrp((CCHAR)(Fdo->StackSize+1),
1798 FALSE);
1799
1800 if (!irp2) {
1801 Irp->IoStatus.Information = 0;
1802 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1803
1804 BAIL_OUT(Irp);
1805 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
1806 return;
1807 }
1808
1809 srb = ExAllocatePoolWithTag(NonPagedPool,
1810 sizeof(SCSI_REQUEST_BLOCK),
1811 CDROM_TAG_SRB);
1812 if (!srb) {
1813 IoFreeIrp(irp2);
1814 Irp->IoStatus.Information = 0;
1815 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1816
1817 BAIL_OUT(Irp);
1818 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
1819 return;
1820 }
1821
1822 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
1823
1824 cdb = (PCDB)srb->Cdb;
1825
1826 //
1827 // Allocate sense buffer.
1828 //
1829
1830 senseBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
1831 SENSE_BUFFER_SIZE,
1832 CDROM_TAG_SENSE_INFO);
1833
1834 if (!senseBuffer) {
1835 ExFreePool(srb);
1836 IoFreeIrp(irp2);
1837 Irp->IoStatus.Information = 0;
1838 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1839
1840 BAIL_OUT(Irp);
1841 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
1842 return;
1843 }
1844
1845 RtlZeroMemory(senseBuffer, SENSE_BUFFER_SIZE);
1846
1847 //
1848 // Set up the irp.
1849 //
1850
1851 IoSetNextIrpStackLocation(irp2);
1852 irp2->IoStatus.Status = STATUS_SUCCESS;
1853 irp2->IoStatus.Information = 0;
1854 irp2->Flags = 0;
1855 irp2->UserBuffer = NULL;
1856
1857 //
1858 // Save the device object and irp in a private stack location.
1859 //
1860
1861 irpStack = IoGetCurrentIrpStackLocation(irp2);
1862 irpStack->DeviceObject = Fdo;
1863 irpStack->Parameters.Others.Argument2 = (PVOID) Irp;
1864
1865 //
1866 // The retry count will be in the real Irp, as the retry logic will
1867 // recreate our private irp.
1868 //
1869
1870 if (!(nextIrpStack->Parameters.Others.Argument1)) {
1871
1872 //
1873 // Only jam this in if it doesn't exist. The completion routines can
1874 // call StartIo directly in the case of retries and resetting it will
1875 // cause infinite loops.
1876 //
1877
1878 nextIrpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
1879 }
1880
1881 //
1882 // keep track of the new irp as Argument3
1883 //
1884
1885 nextIrpStack->Parameters.Others.Argument3 = irp2;
1886
1887
1888 //
1889 // Construct the IRP stack for the lower level driver.
1890 //
1891
1892 irpStack = IoGetNextIrpStackLocation(irp2);
1893 irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
1894 irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
1895 irpStack->Parameters.Scsi.Srb = srb;
1896
1897 IoSetCompletionRoutine(irp2,
1898 CdRomDeviceControlCompletion,
1899 srb,
1900 TRUE,
1901 TRUE,
1902 TRUE);
1903 //
1904 // Setup those fields that are generic to all requests.
1905 //
1906
1907 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
1908 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1909 srb->SrbStatus = srb->ScsiStatus = 0;
1910 srb->NextSrb = 0;
1911 srb->OriginalRequest = irp2;
1912 srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
1913 srb->SenseInfoBuffer = senseBuffer;
1914
1915 switch (currentIrpStack->Parameters.DeviceIoControl.IoControlCode) {
1916
1917
1918 case IOCTL_CDROM_RAW_READ: {
1919
1920 //
1921 // Determine whether the drive is currently in raw or cooked mode,
1922 // and which command to use to read the data.
1923 //
1924
1925 if (!TEST_FLAG(cdData->XAFlags, XA_USE_READ_CD)) {
1926
1927 PRAW_READ_INFO rawReadInfo =
1928 (PRAW_READ_INFO)currentIrpStack->Parameters.DeviceIoControl.Type3InputBuffer;
1929 ULONG maximumTransferLength;
1930 ULONG transferPages;
1931
1932 if (cdData->RawAccess) {
1933
1934 ULONG startingSector;
1935 //UCHAR min, sec, frame;
1936
1937 //
1938 // Free the recently allocated irp, as we don't need it.
1939 //
1940
1941 IoFreeIrp(irp2);
1942
1943 cdb = (PCDB)srb->Cdb;
1944 RtlZeroMemory(cdb, CDB12GENERIC_LENGTH);
1945
1946 //
1947 // Calculate starting offset.
1948 //
1949
1950 startingSector = (ULONG)(rawReadInfo->DiskOffset.QuadPart >> fdoExtension->SectorShift);
1951 transferByteCount = rawReadInfo->SectorCount * RAW_SECTOR_SIZE;
1952 maximumTransferLength = fdoExtension->AdapterDescriptor->MaximumTransferLength;
1953 transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress),
1954 transferByteCount);
1955
1956 //
1957 // Determine if request is within limits imposed by miniport.
1958 //
1959 if (transferByteCount > maximumTransferLength ||
1960 transferPages > fdoExtension->AdapterDescriptor->MaximumPhysicalPages) {
1961
1962 //
1963 // The claim is that this won't happen, and is backed up by
1964 // ActiveMovie usage, which does unbuffered XA reads of 0x18000, yet
1965 // we get only 4 sector requests.
1966 //
1967
1968 ExFreePool(senseBuffer);
1969 ExFreePool(srb);
1970
1971 Irp->IoStatus.Information = 0;
1972 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1973
1974 BAIL_OUT(Irp);
1975 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
1976 return;
1977
1978 }
1979
1980 srb->OriginalRequest = Irp;
1981 srb->SrbFlags = fdoExtension->SrbFlags;
1982 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
1983 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
1984 srb->DataTransferLength = transferByteCount;
1985 srb->TimeOutValue = fdoExtension->TimeOutValue;
1986 srb->CdbLength = 10;
1987 srb->DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
1988
1989 if (rawReadInfo->TrackMode == CDDA) {
1990 if (TEST_FLAG(cdData->XAFlags, XA_PLEXTOR_CDDA)) {
1991
1992 srb->CdbLength = 12;
1993
1994 cdb->PLXTR_READ_CDDA.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
1995 cdb->PLXTR_READ_CDDA.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
1996 cdb->PLXTR_READ_CDDA.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
1997 cdb->PLXTR_READ_CDDA.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
1998
1999 cdb->PLXTR_READ_CDDA.TransferBlockByte3 = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
2000 cdb->PLXTR_READ_CDDA.TransferBlockByte2 = (UCHAR) (rawReadInfo->SectorCount >> 8);
2001 cdb->PLXTR_READ_CDDA.TransferBlockByte1 = 0;
2002 cdb->PLXTR_READ_CDDA.TransferBlockByte0 = 0;
2003
2004 cdb->PLXTR_READ_CDDA.SubCode = 0;
2005 cdb->PLXTR_READ_CDDA.OperationCode = 0xD8;
2006
2007 } else if (TEST_FLAG(cdData->XAFlags, XA_NEC_CDDA)) {
2008
2009 cdb->NEC_READ_CDDA.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
2010 cdb->NEC_READ_CDDA.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
2011 cdb->NEC_READ_CDDA.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
2012 cdb->NEC_READ_CDDA.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
2013
2014 cdb->NEC_READ_CDDA.TransferBlockByte1 = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
2015 cdb->NEC_READ_CDDA.TransferBlockByte0 = (UCHAR) (rawReadInfo->SectorCount >> 8);
2016
2017 cdb->NEC_READ_CDDA.OperationCode = 0xD4;
2018 }
2019 } else {
2020
2021 cdb->CDB10.TransferBlocksMsb = (UCHAR) (rawReadInfo->SectorCount >> 8);
2022 cdb->CDB10.TransferBlocksLsb = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
2023
2024 cdb->CDB10.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
2025 cdb->CDB10.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
2026 cdb->CDB10.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
2027 cdb->CDB10.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
2028
2029 cdb->CDB10.OperationCode = SCSIOP_READ;
2030 }
2031
2032 srb->SrbStatus = srb->ScsiStatus = 0;
2033
2034 nextIrpStack->MajorFunction = IRP_MJ_SCSI;
2035 nextIrpStack->Parameters.Scsi.Srb = srb;
2036
2037 // HACKHACK - REF #0001
2038
2039 //
2040 // Set up IoCompletion routine address.
2041 //
2042
2043 IoSetCompletionRoutine(Irp,
2044 CdRomXACompletion,
2045 srb,
2046 TRUE,
2047 TRUE,
2048 TRUE);
2049
2050 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, Irp);
2051 return;
2052
2053 } else {
2054
2055 transferByteCount = (use6Byte) ? sizeof(ERROR_RECOVERY_DATA) : sizeof(ERROR_RECOVERY_DATA10);
2056 dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
2057 transferByteCount,
2058 CDROM_TAG_RAW );
2059 if (!dataBuffer) {
2060 ExFreePool(senseBuffer);
2061 ExFreePool(srb);
2062 IoFreeIrp(irp2);
2063 Irp->IoStatus.Information = 0;
2064 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2065
2066 BAIL_OUT(Irp);
2067 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
2068 return;
2069
2070 }
2071
2072 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
2073 transferByteCount,
2074 FALSE,
2075 FALSE,
2076 (PIRP) NULL);
2077
2078 if (!irp2->MdlAddress) {
2079 ExFreePool(senseBuffer);
2080 ExFreePool(srb);
2081 ExFreePool(dataBuffer);
2082 IoFreeIrp(irp2);
2083 Irp->IoStatus.Information = 0;
2084 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2085
2086 BAIL_OUT(Irp);
2087 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
2088 return;
2089 }
2090
2091 //
2092 // Prepare the MDL
2093 //
2094
2095 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
2096
2097 srb->DataBuffer = dataBuffer;
2098
2099 //
2100 // Set the new block size in the descriptor.
2101 // This will set the block read size to RAW_SECTOR_SIZE
2102 // TODO: Set density code, based on operation
2103 //
2104
2105 if (use6Byte) {
2106 cdData->BlockDescriptor.BlockLength[0] = (UCHAR)(RAW_SECTOR_SIZE >> 16) & 0xFF;
2107 cdData->BlockDescriptor.BlockLength[1] = (UCHAR)(RAW_SECTOR_SIZE >> 8) & 0xFF;
2108 cdData->BlockDescriptor.BlockLength[2] = (UCHAR)(RAW_SECTOR_SIZE & 0xFF);
2109 cdData->BlockDescriptor.DensityCode = 0;
2110 } else {
2111 cdData->BlockDescriptor10.BlockLength[0] = (UCHAR)(RAW_SECTOR_SIZE >> 16) & 0xFF;
2112 cdData->BlockDescriptor10.BlockLength[1] = (UCHAR)(RAW_SECTOR_SIZE >> 8) & 0xFF;
2113 cdData->BlockDescriptor10.BlockLength[2] = (UCHAR)(RAW_SECTOR_SIZE & 0xFF);
2114 cdData->BlockDescriptor10.DensityCode = 0;
2115 }
2116
2117 //
2118 // Move error page into dataBuffer.
2119 //
2120
2121 RtlCopyMemory(srb->DataBuffer, &cdData->Header, transferByteCount);
2122
2123
2124 //
2125 // Build and send a mode select to switch into raw mode.
2126 //
2127
2128 srb->SrbFlags = fdoExtension->SrbFlags;
2129 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
2130 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_OUT);
2131 srb->DataTransferLength = transferByteCount;
2132 srb->TimeOutValue = fdoExtension->TimeOutValue * 2;
2133
2134 if (use6Byte) {
2135 srb->CdbLength = 6;
2136 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
2137 cdb->MODE_SELECT.PFBit = 1;
2138 cdb->MODE_SELECT.ParameterListLength = (UCHAR)transferByteCount;
2139 } else {
2140
2141 srb->CdbLength = 10;
2142 cdb->MODE_SELECT10.OperationCode = SCSIOP_MODE_SELECT10;
2143 cdb->MODE_SELECT10.PFBit = 1;
2144 cdb->MODE_SELECT10.ParameterListLength[0] = (UCHAR)(transferByteCount >> 8);
2145 cdb->MODE_SELECT10.ParameterListLength[1] = (UCHAR)(transferByteCount & 0xFF);
2146 }
2147
2148 //
2149 // Update completion routine.
2150 //
2151
2152 IoSetCompletionRoutine(irp2,
2153 CdRomSwitchModeCompletion,
2154 srb,
2155 TRUE,
2156 TRUE,
2157 TRUE);
2158
2159 }
2160
2161 } else {
2162
2163 PRAW_READ_INFO rawReadInfo =
2164 (PRAW_READ_INFO)currentIrpStack->Parameters.DeviceIoControl.Type3InputBuffer;
2165 ULONG startingSector;
2166
2167 //
2168 // Free the recently allocated irp, as we don't need it.
2169 //
2170
2171 IoFreeIrp(irp2);
2172
2173 cdb = (PCDB)srb->Cdb;
2174 RtlZeroMemory(cdb, CDB12GENERIC_LENGTH);
2175
2176
2177 //
2178 // Calculate starting offset.
2179 //
2180
2181 startingSector = (ULONG)(rawReadInfo->DiskOffset.QuadPart >> fdoExtension->SectorShift);
2182 transferByteCount = rawReadInfo->SectorCount * RAW_SECTOR_SIZE;
2183
2184 srb->OriginalRequest = Irp;
2185 srb->SrbFlags = fdoExtension->SrbFlags;
2186 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
2187 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
2188 srb->DataTransferLength = transferByteCount;
2189 srb->TimeOutValue = fdoExtension->TimeOutValue;
2190 srb->DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
2191 srb->CdbLength = 12;
2192 srb->SrbStatus = srb->ScsiStatus = 0;
2193
2194 //
2195 // Fill in CDB fields.
2196 //
2197
2198 cdb = (PCDB)srb->Cdb;
2199
2200
2201 cdb->READ_CD.TransferBlocks[2] = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
2202 cdb->READ_CD.TransferBlocks[1] = (UCHAR) (rawReadInfo->SectorCount >> 8 );
2203 cdb->READ_CD.TransferBlocks[0] = (UCHAR) (rawReadInfo->SectorCount >> 16);
2204
2205
2206 cdb->READ_CD.StartingLBA[3] = (UCHAR) (startingSector & 0xFF);
2207 cdb->READ_CD.StartingLBA[2] = (UCHAR) ((startingSector >> 8));
2208 cdb->READ_CD.StartingLBA[1] = (UCHAR) ((startingSector >> 16));
2209 cdb->READ_CD.StartingLBA[0] = (UCHAR) ((startingSector >> 24));
2210
2211 //
2212 // Setup cdb depending upon the sector type we want.
2213 //
2214
2215 switch (rawReadInfo->TrackMode) {
2216 case CDDA:
2217
2218 cdb->READ_CD.ExpectedSectorType = CD_DA_SECTOR;
2219 cdb->READ_CD.IncludeUserData = 1;
2220 cdb->READ_CD.HeaderCode = 3;
2221 cdb->READ_CD.IncludeSyncData = 1;
2222 break;
2223
2224 case YellowMode2:
2225
2226 cdb->READ_CD.ExpectedSectorType = YELLOW_MODE2_SECTOR;
2227 cdb->READ_CD.IncludeUserData = 1;
2228 cdb->READ_CD.HeaderCode = 1;
2229 cdb->READ_CD.IncludeSyncData = 1;
2230 break;
2231
2232 case XAForm2:
2233
2234 cdb->READ_CD.ExpectedSectorType = FORM2_MODE2_SECTOR;
2235 cdb->READ_CD.IncludeUserData = 1;
2236 cdb->READ_CD.HeaderCode = 3;
2237 cdb->READ_CD.IncludeSyncData = 1;
2238 break;
2239
2240 default:
2241 ExFreePool(senseBuffer);
2242 ExFreePool(srb);
2243 Irp->IoStatus.Information = 0;
2244 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
2245
2246 BAIL_OUT(Irp);
2247 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
2248 return;
2249 }
2250
2251 cdb->READ_CD.OperationCode = SCSIOP_READ_CD;
2252
2253 nextIrpStack->MajorFunction = IRP_MJ_SCSI;
2254 nextIrpStack->Parameters.Scsi.Srb = srb;
2255
2256 // HACKHACK - REF #0001
2257
2258 //
2259 // Set up IoCompletion routine address.
2260 //
2261
2262 IoSetCompletionRoutine(Irp,
2263 CdRomXACompletion,
2264 srb,
2265 TRUE,
2266 TRUE,
2267 TRUE);
2268
2269 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, Irp);
2270 return;
2271
2272 }
2273
2274 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
2275 return;
2276 }
2277
2278 //
2279 // the _EX version does the same thing on the front end
2280 //
2281
2282 case IOCTL_DISK_GET_LENGTH_INFO:
2283 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX:
2284 case IOCTL_DISK_GET_DRIVE_GEOMETRY:
2285 case IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX:
2286 case IOCTL_CDROM_GET_DRIVE_GEOMETRY: {
2287
2288 //
2289 // Issue ReadCapacity to update device extension
2290 // with information for current media.
2291 //
2292
2293 TraceLog((CdromDebugError,
2294 "CdRomStartIo: Get drive geometry/length "
2295 "info (%p)\n", Irp));
2296
2297 //
2298 // setup remaining srb and cdb parameters.
2299 //
2300
2301 srb->SrbFlags = fdoExtension->SrbFlags;
2302 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
2303 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
2304 srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
2305 srb->CdbLength = 10;
2306 srb->TimeOutValue = fdoExtension->TimeOutValue;
2307
2308 dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
2309 sizeof(READ_CAPACITY_DATA),
2310 CDROM_TAG_READ_CAP);
2311 if (!dataBuffer) {
2312 ExFreePool(senseBuffer);
2313 ExFreePool(srb);
2314 IoFreeIrp(irp2);
2315 Irp->IoStatus.Information = 0;
2316 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2317
2318 BAIL_OUT(Irp);
2319 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
2320 return;
2321
2322 }
2323
2324 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
2325 sizeof(READ_CAPACITY_DATA),
2326 FALSE,
2327 FALSE,
2328 (PIRP) NULL);
2329
2330 if (!irp2->MdlAddress) {
2331 ExFreePool(senseBuffer);
2332 ExFreePool(srb);
2333 ExFreePool(dataBuffer);
2334 IoFreeIrp(irp2);
2335 Irp->IoStatus.Information = 0;
2336 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2337
2338 BAIL_OUT(Irp);
2339 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
2340 return;
2341 }
2342
2343 //
2344 // Prepare the MDL
2345 //
2346
2347 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
2348
2349 srb->DataBuffer = dataBuffer;
2350 cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
2351
2352 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
2353 return;
2354 }
2355
2356 case IOCTL_CDROM_GET_CONFIGURATION: {
2357
2358 PGET_CONFIGURATION_IOCTL_INPUT inputBuffer;
2359
2360 TraceLog((CdromDebugError,
2361 "CdRomStartIo: Get configuration (%p)\n", Irp));
2362
2363 if (!cdData->Mmc.IsMmc) {
2364 ExFreePool(senseBuffer);
2365 ExFreePool(srb);
2366 IoFreeIrp(irp2);
2367 Irp->IoStatus.Information = 0;
2368 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
2369 BAIL_OUT(Irp);
2370 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
2371 return;
2372 }
2373
2374 transferByteCount = currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
2375
2376 dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
2377 transferByteCount,
2378 CDROM_TAG_GET_CONFIG);
2379 if (!dataBuffer) {
2380 ExFreePool(senseBuffer);
2381 ExFreePool(srb);
2382 IoFreeIrp(irp2);
2383 Irp->IoStatus.Information = 0;
2384 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2385 BAIL_OUT(Irp);
2386 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
2387 return;
2388 }
2389
2390 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
2391 transferByteCount,
2392 FALSE,
2393 FALSE,
2394 (PIRP) NULL);
2395 if (!irp2->MdlAddress) {
2396 ExFreePool(dataBuffer);
2397 ExFreePool(senseBuffer);
2398 ExFreePool(srb);
2399 IoFreeIrp(irp2);
2400 Irp->IoStatus.Information = 0;
2401 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2402 BAIL_OUT(Irp);
2403 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
2404 return;
2405 }
2406
2407 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
2408
2409 //
2410 // setup remaining srb and cdb parameters
2411 //
2412
2413 srb->SrbFlags = fdoExtension->SrbFlags;
2414 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
2415 srb->DataTransferLength = transferByteCount;
2416 srb->CdbLength = 10;
2417 srb->TimeOutValue = fdoExtension->TimeOutValue;
2418 srb->DataBuffer = dataBuffer;
2419
2420 cdb->GET_CONFIGURATION.OperationCode = SCSIOP_GET_CONFIGURATION;
2421 cdb->GET_CONFIGURATION.AllocationLength[0] = (UCHAR)(transferByteCount >> 8);
2422 cdb->GET_CONFIGURATION.AllocationLength[1] = (UCHAR)(transferByteCount & 0xff);
2423
2424 inputBuffer = (PGET_CONFIGURATION_IOCTL_INPUT)Irp->AssociatedIrp.SystemBuffer;
2425 cdb->GET_CONFIGURATION.StartingFeature[0] = (UCHAR)(inputBuffer->Feature >> 8);
2426 cdb->GET_CONFIGURATION.StartingFeature[1] = (UCHAR)(inputBuffer->Feature & 0xff);
2427 cdb->GET_CONFIGURATION.RequestType = (UCHAR)(inputBuffer->RequestType);
2428
2429 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
2430 return;
2431 }
2432
2433 case IOCTL_DISK_VERIFY: {
2434
2435 PVERIFY_INFORMATION verifyInfo = Irp->AssociatedIrp.SystemBuffer;
2436 LARGE_INTEGER byteOffset;
2437 ULONG sectorOffset;
2438 USHORT sectorCount;
2439
2440 if (!cdData->Mmc.WriteAllowed) {
2441 ExFreePool(senseBuffer);
2442 ExFreePool(srb);
2443 IoFreeIrp(irp2);
2444 Irp->IoStatus.Information = 0;
2445 Irp->IoStatus.Status = STATUS_MEDIA_WRITE_PROTECTED;
2446 BAIL_OUT(Irp);
2447 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
2448 return;
2449 }
2450 //
2451 // Verify sectors
2452 //
2453
2454 srb->CdbLength = 10;
2455
2456 cdb->CDB10.OperationCode = SCSIOP_VERIFY;
2457
2458 //
2459 // Add disk offset to starting sector.
2460 //
2461
2462 byteOffset.QuadPart = commonExtension->StartingOffset.QuadPart +
2463 verifyInfo->StartingOffset.QuadPart;
2464
2465 //
2466 // Convert byte offset to sector offset.
2467 //
2468
2469 sectorOffset = (ULONG)(byteOffset.QuadPart >> fdoExtension->SectorShift);
2470
2471 //
2472 // Convert ULONG byte count to USHORT sector count.
2473 //
2474
2475 sectorCount = (USHORT)(verifyInfo->Length >> fdoExtension->SectorShift);
2476
2477 //
2478 // Move little endian values into CDB in big endian format.
2479 //
2480
2481 cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&sectorOffset)->Byte3;
2482 cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&sectorOffset)->Byte2;
2483 cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&sectorOffset)->Byte1;
2484 cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&sectorOffset)->Byte0;
2485
2486 cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&sectorCount)->Byte1;
2487 cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&sectorCount)->Byte0;
2488
2489 //
2490 // The verify command is used by the NT FORMAT utility and
2491 // requests are sent down for 5% of the volume size. The
2492 // request timeout value is calculated based on the number of
2493 // sectors verified.
2494 //
2495
2496 srb->TimeOutValue = ((sectorCount + 0x7F) >> 7) *
2497 fdoExtension->TimeOutValue;
2498
2499 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
2500 return;
2501 }
2502
2503 case IOCTL_STORAGE_CHECK_VERIFY:
2504 case IOCTL_DISK_CHECK_VERIFY:
2505 case IOCTL_CDROM_CHECK_VERIFY: {
2506
2507 //
2508 // Since a test unit ready is about to be performed, reset the
2509 // timer value to decrease the opportunities for it to race with
2510 // this code.
2511 //
2512
2513 ClassResetMediaChangeTimer(fdoExtension);
2514
2515 //
2516 // Set up the SRB/CDB
2517 //
2518
2519 srb->CdbLength = 6;
2520 cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
2521 srb->TimeOutValue = fdoExtension->TimeOutValue * 2;
2522 srb->SrbFlags = fdoExtension->SrbFlags;
2523 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
2524 SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER);
2525
2526
2527 TraceLog((CdromDebugTrace,
2528 "CdRomStartIo: [%p] Sending CHECK_VERIFY irp %p\n",
2529 Irp, irp2));
2530 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
2531 return;
2532 }
2533
2534 case IOCTL_DVD_READ_STRUCTURE: {
2535
2536 CdRomDeviceControlDvdReadStructure(Fdo, Irp, irp2, srb);
2537 return;
2538
2539 }
2540
2541 case IOCTL_DVD_END_SESSION: {
2542 CdRomDeviceControlDvdEndSession(Fdo, Irp, irp2, srb);
2543 return;
2544 }
2545
2546 case IOCTL_DVD_START_SESSION:
2547 case IOCTL_DVD_READ_KEY: {
2548
2549 CdRomDeviceControlDvdStartSessionReadKey(Fdo, Irp, irp2, srb);
2550 return;
2551
2552 }
2553
2554
2555 case IOCTL_DVD_SEND_KEY:
2556 case IOCTL_DVD_SEND_KEY2: {
2557
2558 CdRomDeviceControlDvdSendKey (Fdo, Irp, irp2, srb);
2559 return;
2560
2561
2562 }
2563
2564 case IOCTL_CDROM_READ_TOC_EX: {
2565
2566 PCDROM_READ_TOC_EX inputBuffer = Irp->AssociatedIrp.SystemBuffer;
2567
2568 transferByteCount = currentIrpStack->Parameters.Read.Length;
2569
2570 dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
2571 transferByteCount,
2572 CDROM_TAG_TOC);
2573 if (!dataBuffer) {
2574 ExFreePool(senseBuffer);
2575 ExFreePool(srb);
2576 IoFreeIrp(irp2);
2577 Irp->IoStatus.Information = 0;
2578 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2579
2580 BAIL_OUT(Irp);
2581 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
2582 return;
2583
2584 }
2585
2586 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
2587 transferByteCount,
2588 FALSE,
2589 FALSE,
2590 (PIRP) NULL);
2591
2592 if (!irp2->MdlAddress) {
2593 ExFreePool(senseBuffer);
2594 ExFreePool(srb);
2595 ExFreePool(dataBuffer);
2596 IoFreeIrp(irp2);
2597 Irp->IoStatus.Information = 0;
2598 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2599
2600 BAIL_OUT(Irp);
2601 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
2602 return;
2603 }
2604
2605 //
2606 // setup the request per user request
2607 // do validity checking in devctl dispatch, not here
2608 //
2609
2610 cdb->READ_TOC.OperationCode = SCSIOP_READ_TOC;
2611 cdb->READ_TOC.Msf = inputBuffer->Msf;
2612 cdb->READ_TOC.Format2 = inputBuffer->Format;
2613 cdb->READ_TOC.StartingTrack = inputBuffer->SessionTrack;
2614 cdb->READ_TOC.AllocationLength[0] = (UCHAR)(transferByteCount >> 8);
2615 cdb->READ_TOC.AllocationLength[1] = (UCHAR)(transferByteCount & 0xff);
2616
2617 //
2618 // Prepare the MDL
2619 //
2620
2621 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
2622
2623 //
2624 // do the standard stuff....
2625 //
2626
2627 srb->SrbFlags = fdoExtension->SrbFlags;
2628 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
2629 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
2630 srb->DataTransferLength = transferByteCount;
2631 srb->CdbLength = 10;
2632 srb->TimeOutValue = fdoExtension->TimeOutValue;
2633 srb->DataBuffer = dataBuffer;
2634
2635 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
2636 return;
2637 }
2638
2639 case IOCTL_CDROM_GET_LAST_SESSION:
2640 case IOCTL_CDROM_READ_TOC: {
2641
2642 if (currentIrpStack->Parameters.DeviceIoControl.IoControlCode ==
2643 IOCTL_CDROM_GET_LAST_SESSION) {
2644
2645 //
2646 // Set format to return first and last session numbers.
2647 //
2648
2649 cdb->READ_TOC.Format = CDROM_READ_TOC_EX_FORMAT_SESSION;
2650
2651 } else {
2652
2653 //
2654 // Use MSF addressing
2655 //
2656
2657 cdb->READ_TOC.Msf = 1;
2658
2659 }
2660
2661
2662 transferByteCount =
2663 currentIrpStack->Parameters.Read.Length >
2664 sizeof(CDROM_TOC) ? sizeof(CDROM_TOC):
2665 currentIrpStack->Parameters.Read.Length;
2666
2667 //
2668 // Set size of TOC structure.
2669 //
2670
2671 cdb->READ_TOC.AllocationLength[0] = (UCHAR) (transferByteCount >> 8);
2672 cdb->READ_TOC.AllocationLength[1] = (UCHAR) (transferByteCount & 0xFF);
2673
2674 //
2675 // setup remaining srb and cdb parameters.
2676 //
2677
2678 srb->SrbFlags = fdoExtension->SrbFlags;
2679 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
2680 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
2681 srb->DataTransferLength = transferByteCount;
2682 srb->CdbLength = 10;
2683 srb->TimeOutValue = fdoExtension->TimeOutValue;
2684
2685 dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
2686 transferByteCount,
2687 CDROM_TAG_TOC);
2688 if (!dataBuffer) {
2689 ExFreePool(senseBuffer);
2690 ExFreePool(srb);
2691 IoFreeIrp(irp2);
2692 Irp->IoStatus.Information = 0;
2693 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2694
2695 BAIL_OUT(Irp);
2696 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
2697 return;
2698
2699 }
2700
2701 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
2702 transferByteCount,
2703 FALSE,
2704 FALSE,
2705 (PIRP) NULL);
2706
2707 if (!irp2->MdlAddress) {
2708 ExFreePool(senseBuffer);
2709 ExFreePool(srb);
2710 ExFreePool(dataBuffer);
2711 IoFreeIrp(irp2);
2712 Irp->IoStatus.Information = 0;
2713 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2714
2715 BAIL_OUT(Irp);
2716 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
2717 return;
2718 }
2719
2720 //
2721 // Prepare the MDL
2722 //
2723
2724 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
2725
2726 srb->DataBuffer = dataBuffer;
2727 cdb->READ_TOC.OperationCode = SCSIOP_READ_TOC;
2728
2729 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
2730 return;
2731
2732 }
2733
2734 case IOCTL_CDROM_PLAY_AUDIO_MSF: {
2735
2736 PCDROM_PLAY_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
2737
2738 //
2739 // Set up the SRB/CDB
2740 //
2741
2742 srb->CdbLength = 10;
2743 cdb->PLAY_AUDIO_MSF.OperationCode = SCSIOP_PLAY_AUDIO_MSF;
2744
2745 cdb->PLAY_AUDIO_MSF.StartingM = inputBuffer->StartingM;
2746 cdb->PLAY_AUDIO_MSF.StartingS = inputBuffer->StartingS;
2747 cdb->PLAY_AUDIO_MSF.StartingF = inputBuffer->StartingF;
2748
2749 cdb->PLAY_AUDIO_MSF.EndingM = inputBuffer->EndingM;
2750 cdb->PLAY_AUDIO_MSF.EndingS = inputBuffer->EndingS;
2751 cdb->PLAY_AUDIO_MSF.EndingF = inputBuffer->EndingF;
2752
2753 srb->TimeOutValue = fdoExtension->TimeOutValue;
2754 srb->SrbFlags = fdoExtension->SrbFlags;
2755 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
2756 SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER);
2757
2758 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
2759 return;
2760
2761 }
2762
2763 case IOCTL_CDROM_READ_Q_CHANNEL: {
2764
2765 #if 0
2766 PSUB_Q_CHANNEL_DATA userChannelData =
2767 Irp->AssociatedIrp.SystemBuffer;
2768 #endif
2769 PCDROM_SUB_Q_DATA_FORMAT inputBuffer =
2770 Irp->AssociatedIrp.SystemBuffer;
2771
2772 //
2773 // Allocate buffer for subq channel information.
2774 //
2775
2776 dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
2777 sizeof(SUB_Q_CHANNEL_DATA),
2778 CDROM_TAG_SUB_Q);
2779
2780 if (!dataBuffer) {
2781 ExFreePool(senseBuffer);
2782 ExFreePool(srb);
2783 IoFreeIrp(irp2);
2784 Irp->IoStatus.Information = 0;
2785 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2786
2787 BAIL_OUT(Irp);
2788 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
2789 return;
2790
2791 }
2792
2793 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
2794 sizeof(SUB_Q_CHANNEL_DATA),
2795 FALSE,
2796 FALSE,
2797 (PIRP) NULL);
2798
2799 if (!irp2->MdlAddress) {
2800 ExFreePool(senseBuffer);
2801 ExFreePool(srb);
2802 ExFreePool(dataBuffer);
2803 IoFreeIrp(irp2);
2804 Irp->IoStatus.Information = 0;
2805 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2806
2807 BAIL_OUT(Irp);
2808 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
2809 return;
2810 }
2811
2812 //
2813 // Prepare the MDL
2814 //
2815
2816 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
2817
2818 srb->DataBuffer = dataBuffer;
2819
2820 //
2821 // Always logical unit 0, but only use MSF addressing
2822 // for IOCTL_CDROM_CURRENT_POSITION
2823 //
2824
2825 if (inputBuffer->Format==IOCTL_CDROM_CURRENT_POSITION)
2826 cdb->SUBCHANNEL.Msf = CDB_USE_MSF;
2827
2828 //
2829 // Return subchannel data
2830 //
2831
2832 cdb->SUBCHANNEL.SubQ = CDB_SUBCHANNEL_BLOCK;
2833
2834 //
2835 // Specify format of information to return
2836 //
2837
2838 cdb->SUBCHANNEL.Format = inputBuffer->Format;
2839
2840 //
2841 // Specify which track to access (only used by Track ISRC reads)
2842 //
2843
2844 if (inputBuffer->Format==IOCTL_CDROM_TRACK_ISRC) {
2845 cdb->SUBCHANNEL.TrackNumber = inputBuffer->Track;
2846 }
2847
2848 //
2849 // Set size of channel data -- however, this is dependent on
2850 // what information we are requesting (which Format)
2851 //
2852
2853 switch( inputBuffer->Format ) {
2854
2855 case IOCTL_CDROM_CURRENT_POSITION:
2856 transferByteCount = sizeof(SUB_Q_CURRENT_POSITION);
2857 break;
2858
2859 case IOCTL_CDROM_MEDIA_CATALOG:
2860 transferByteCount = sizeof(SUB_Q_MEDIA_CATALOG_NUMBER);
2861 break;
2862
2863 case IOCTL_CDROM_TRACK_ISRC:
2864 transferByteCount = sizeof(SUB_Q_TRACK_ISRC);
2865 break;
2866 }
2867
2868 cdb->SUBCHANNEL.AllocationLength[0] = (UCHAR) (transferByteCount >> 8);
2869 cdb->SUBCHANNEL.AllocationLength[1] = (UCHAR) (transferByteCount & 0xFF);
2870 cdb->SUBCHANNEL.OperationCode = SCSIOP_READ_SUB_CHANNEL;
2871 srb->SrbFlags = fdoExtension->SrbFlags;
2872 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
2873 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
2874 srb->DataTransferLength = transferByteCount;
2875 srb->CdbLength = 10;
2876 srb->TimeOutValue = fdoExtension->TimeOutValue;
2877
2878 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
2879 return;
2880
2881 }
2882
2883 case IOCTL_CDROM_PAUSE_AUDIO: {
2884
2885 cdb->PAUSE_RESUME.OperationCode = SCSIOP_PAUSE_RESUME;
2886 cdb->PAUSE_RESUME.Action = CDB_AUDIO_PAUSE;
2887
2888 srb->CdbLength = 10;
2889 srb->TimeOutValue = fdoExtension->TimeOutValue;
2890 srb->SrbFlags = fdoExtension->SrbFlags;
2891 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
2892 SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER);
2893
2894 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
2895 return;
2896 }
2897
2898 case IOCTL_CDROM_RESUME_AUDIO: {
2899
2900 cdb->PAUSE_RESUME.OperationCode = SCSIOP_PAUSE_RESUME;
2901 cdb->PAUSE_RESUME.Action = CDB_AUDIO_RESUME;
2902
2903 srb->CdbLength = 10;
2904 srb->TimeOutValue = fdoExtension->TimeOutValue;
2905 srb->SrbFlags = fdoExtension->SrbFlags;
2906 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
2907 SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER);
2908
2909 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
2910 return;
2911 }
2912
2913 case IOCTL_CDROM_SEEK_AUDIO_MSF: {
2914
2915 PCDROM_SEEK_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
2916 ULONG logicalBlockAddress;
2917
2918 logicalBlockAddress = MSF_TO_LBA(inputBuffer->M, inputBuffer->S, inputBuffer->F);
2919
2920 cdb->SEEK.OperationCode = SCSIOP_SEEK;
2921 cdb->SEEK.LogicalBlockAddress[0] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte3;
2922 cdb->SEEK.LogicalBlockAddress[1] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte2;
2923 cdb->SEEK.LogicalBlockAddress[2] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte1;
2924 cdb->SEEK.LogicalBlockAddress[3] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte0;
2925
2926 srb->CdbLength = 10;
2927 srb->TimeOutValue = fdoExtension->TimeOutValue;
2928 srb->SrbFlags = fdoExtension->SrbFlags;
2929 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
2930 SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER);
2931
2932 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
2933 return;
2934
2935 }
2936
2937 case IOCTL_CDROM_STOP_AUDIO: {
2938
2939 cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
2940 cdb->START_STOP.Immediate = 1;
2941 cdb->START_STOP.Start = 0;
2942 cdb->START_STOP.LoadEject = 0;
2943
2944 srb->CdbLength = 6;
2945 srb->TimeOutValue = fdoExtension->TimeOutValue;
2946
2947 srb->SrbFlags = fdoExtension->SrbFlags;
2948 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
2949 SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER);
2950
2951 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
2952 return;
2953 }
2954
2955 case IOCTL_CDROM_GET_CONTROL: {
2956
2957 //PAUDIO_OUTPUT audioOutput;
2958 //PCDROM_AUDIO_CONTROL audioControl = Irp->AssociatedIrp.SystemBuffer;
2959
2960 //
2961 // Allocate buffer for volume control information.
2962 //
2963
2964 dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
2965 MODE_DATA_SIZE,
2966 CDROM_TAG_VOLUME);
2967
2968 if (!dataBuffer) {
2969 ExFreePool(senseBuffer);
2970 ExFreePool(srb);
2971 IoFreeIrp(irp2);
2972 Irp->IoStatus.Information = 0;
2973 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2974
2975 BAIL_OUT(Irp);
2976 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
2977 return;
2978
2979 }
2980
2981 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
2982 MODE_DATA_SIZE,
2983 FALSE,
2984 FALSE,
2985 (PIRP) NULL);
2986
2987 if (!irp2->MdlAddress) {
2988 ExFreePool(senseBuffer);
2989 ExFreePool(srb);
2990 ExFreePool(dataBuffer);
2991 IoFreeIrp(irp2);
2992 Irp->IoStatus.Information = 0;
2993 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2994
2995 BAIL_OUT(Irp);
2996 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
2997 return;
2998 }
2999
3000 //
3001 // Prepare the MDL
3002 //
3003
3004 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
3005 srb->DataBuffer = dataBuffer;
3006
3007 RtlZeroMemory(dataBuffer, MODE_DATA_SIZE);
3008
3009 //
3010 // Setup for either 6 or 10 byte CDBs.
3011 //
3012
3013 if (use6Byte) {
3014
3015 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
3016 cdb->MODE_SENSE.PageCode = CDROM_AUDIO_CONTROL_PAGE;
3017 cdb->MODE_SENSE.AllocationLength = MODE_DATA_SIZE;
3018
3019 //
3020 // Disable block descriptors.
3021 //
3022
3023 cdb->MODE_SENSE.Dbd = TRUE;
3024
3025 srb->CdbLength = 6;
3026 } else {
3027
3028 cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
3029 cdb->MODE_SENSE10.PageCode = CDROM_AUDIO_CONTROL_PAGE;
3030 cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(MODE_DATA_SIZE >> 8);
3031 cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(MODE_DATA_SIZE & 0xFF);
3032
3033 //
3034 // Disable block descriptors.
3035 //
3036
3037 cdb->MODE_SENSE10.Dbd = TRUE;
3038
3039 srb->CdbLength = 10;
3040 }
3041
3042 srb->TimeOutValue = fdoExtension->TimeOutValue;
3043 srb->DataTransferLength = MODE_DATA_SIZE;
3044 srb->SrbFlags = fdoExtension->SrbFlags;
3045 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
3046 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
3047
3048 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
3049 return;
3050
3051 }
3052
3053 case IOCTL_CDROM_GET_VOLUME:
3054 case IOCTL_CDROM_SET_VOLUME: {
3055
3056 dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
3057 MODE_DATA_SIZE,
3058 CDROM_TAG_VOLUME);
3059
3060 if (!dataBuffer) {
3061 ExFreePool(senseBuffer);
3062 ExFreePool(srb);
3063 IoFreeIrp(irp2);
3064 Irp->IoStatus.Information = 0;
3065 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
3066
3067 BAIL_OUT(Irp);
3068 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
3069 return;
3070 }
3071
3072 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
3073 MODE_DATA_SIZE,
3074 FALSE,
3075 FALSE,
3076 (PIRP) NULL);
3077
3078 if (!irp2->MdlAddress) {
3079 ExFreePool(senseBuffer);
3080 ExFreePool(srb);
3081 ExFreePool(dataBuffer);
3082 IoFreeIrp(irp2);
3083 Irp->IoStatus.Information = 0;
3084 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
3085
3086 BAIL_OUT(Irp);
3087 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
3088 return;
3089 }
3090
3091 //
3092 // Prepare the MDL
3093 //
3094
3095 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
3096 srb->DataBuffer = dataBuffer;
3097
3098 RtlZeroMemory(dataBuffer, MODE_DATA_SIZE);
3099
3100
3101 if (use6Byte) {
3102
3103 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
3104 cdb->MODE_SENSE.PageCode = CDROM_AUDIO_CONTROL_PAGE;
3105 cdb->MODE_SENSE.AllocationLength = MODE_DATA_SIZE;
3106
3107 srb->CdbLength = 6;
3108
3109 } else {
3110
3111 cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
3112 cdb->MODE_SENSE10.PageCode = CDROM_AUDIO_CONTROL_PAGE;
3113 cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(MODE_DATA_SIZE >> 8);
3114 cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(MODE_DATA_SIZE & 0xFF);
3115
3116 srb->CdbLength = 10;
3117 }
3118
3119 srb->TimeOutValue = fdoExtension->TimeOutValue;
3120 srb->DataTransferLength = MODE_DATA_SIZE;
3121 srb->SrbFlags = fdoExtension->SrbFlags;
3122 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
3123 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
3124
3125 if (currentIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_SET_VOLUME) {
3126
3127 //
3128 // Setup a different completion routine as the mode sense data is needed in order
3129 // to send the mode select.
3130 //
3131
3132 IoSetCompletionRoutine(irp2,
3133 CdRomSetVolumeIntermediateCompletion,
3134 srb,
3135 TRUE,
3136 TRUE,
3137 TRUE);
3138
3139 }
3140
3141 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
3142 return;
3143
3144 }
3145
3146 case IOCTL_STORAGE_SET_READ_AHEAD: {
3147
3148 PSTORAGE_SET_READ_AHEAD readAhead = Irp->AssociatedIrp.SystemBuffer;
3149
3150 ULONG blockAddress;
3151 PFOUR_BYTE fourByte = (PFOUR_BYTE) &blockAddress;
3152
3153 //
3154 // setup the SRB for a set readahead command
3155 //
3156
3157 cdb->SET_READ_AHEAD.OperationCode = SCSIOP_SET_READ_AHEAD;
3158
3159 blockAddress = (ULONG) (readAhead->TriggerAddress.QuadPart >>
3160 fdoExtension->SectorShift);
3161
3162 cdb->SET_READ_AHEAD.TriggerLBA[0] = fourByte->Byte3;
3163 cdb->SET_READ_AHEAD.TriggerLBA[1] = fourByte->Byte2;
3164 cdb->SET_READ_AHEAD.TriggerLBA[2] = fourByte->Byte1;
3165 cdb->SET_READ_AHEAD.TriggerLBA[3] = fourByte->Byte0;
3166
3167 blockAddress = (ULONG) (readAhead->TargetAddress.QuadPart >>
3168 fdoExtension->SectorShift);
3169
3170 cdb->SET_READ_AHEAD.ReadAheadLBA[0] = fourByte->Byte3;
3171 cdb->SET_READ_AHEAD.ReadAheadLBA[1] = fourByte->Byte2;
3172 cdb->SET_READ_AHEAD.ReadAheadLBA[2] = fourByte->Byte1;
3173 cdb->SET_READ_AHEAD.ReadAheadLBA[3] = fourByte->Byte0;
3174
3175 srb->CdbLength = 12;
3176 srb->TimeOutValue = fdoExtension->TimeOutValue;
3177
3178 srb->SrbFlags = fdoExtension->SrbFlags;
3179 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
3180 SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER);
3181
3182 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
3183 return;
3184 }
3185
3186 case IOCTL_DISK_GET_DRIVE_LAYOUT:
3187 case IOCTL_DISK_GET_DRIVE_LAYOUT_EX:
3188 case IOCTL_DISK_GET_PARTITION_INFO:
3189 case IOCTL_DISK_GET_PARTITION_INFO_EX: {
3190
3191 ASSERT(irp2);
3192 ASSERT(senseBuffer);
3193 ASSERT(srb);
3194
3195 ExFreePool(srb);
3196 ExFreePool(senseBuffer);
3197 IoFreeIrp(irp2);
3198
3199 //
3200 // NOTE: should probably update the media's capacity first...
3201 //
3202
3203 CdromFakePartitionInfo(commonExtension, Irp);
3204 return;
3205 }
3206
3207 case IOCTL_DISK_IS_WRITABLE: {
3208
3209 TraceLog((CdromDebugWarning,
3210 "CdRomStartIo: DiskIsWritable (%p) - returning %s\n",
3211 Irp, (cdData->Mmc.WriteAllowed ? "TRUE" : "false")));
3212
3213 ASSERT(irp2);
3214 ASSERT(senseBuffer);
3215 ASSERT(srb);
3216
3217 ExFreePool(srb);
3218 ExFreePool(senseBuffer);
3219 IoFreeIrp(irp2);
3220
3221 Irp->IoStatus.Information = 0;
3222 if (cdData->Mmc.WriteAllowed) {
3223 Irp->IoStatus.Status = STATUS_SUCCESS;
3224 } else {
3225 Irp->IoStatus.Status = STATUS_MEDIA_WRITE_PROTECTED;
3226 }
3227 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
3228 return;
3229 }
3230
3231 default: {
3232
3233 UCHAR uniqueAddress;
3234
3235 //
3236 // Just complete the request - CdRomClassIoctlCompletion will take
3237 // care of it for us
3238 //
3239 // NOTE: THIS IS A SYNCHRONIZATION METHOD!!!
3240 //
3241
3242 //
3243 // Acquire a new copy of the lock so that ClassCompleteRequest
3244 // doesn't get confused when we complete the other request while
3245 // holding the lock.
3246 //
3247
3248 //
3249 // NOTE: CdRomDeviceControlDispatch/CdRomDeviceControlCompletion
3250 // wait for the event and eventually calls
3251 // IoStartNextPacket()
3252 //
3253
3254 ASSERT(irp2);
3255 ASSERT(senseBuffer);
3256 ASSERT(srb);
3257
3258 ExFreePool(srb);
3259 ExFreePool(senseBuffer);
3260 IoFreeIrp(irp2);
3261
3262
3263
3264 ClassAcquireRemoveLock(Fdo, (PIRP)&uniqueAddress);
3265 ClassReleaseRemoveLock(Fdo, Irp);
3266 ClassCompleteRequest(Fdo, Irp, IO_NO_INCREMENT);
3267 ClassReleaseRemoveLock(Fdo, (PIRP)&uniqueAddress);
3268 return;
3269 }
3270
3271 } // end switch()
3272 } else if (currentIrpStack->MajorFunction == IRP_MJ_SHUTDOWN ||
3273 currentIrpStack->MajorFunction == IRP_MJ_FLUSH_BUFFERS) {
3274
3275 currentIrpStack->Parameters.Others.Argument1 = 0;
3276 Irp->IoStatus.Status = STATUS_SUCCESS;
3277 CdRomShutdownFlushCompletion(Fdo, NULL, Irp);
3278 return;
3279
3280 }
3281
3282 //
3283 // If a read or an unhandled IRP_MJ_XX, end up here. The unhandled IRP_MJ's
3284 // are expected and composed of AutoRun Irps, at present.
3285 //
3286
3287 IoCallDriver(commonExtension->LowerDeviceObject, Irp);
3288 return;
3289 }
3290
3291 NTSTATUS
3292 NTAPI
3293 CdRomReadWriteVerification(
3294 IN PDEVICE_OBJECT DeviceObject,
3295 IN PIRP Irp
3296 )
3297
3298 /*++
3299
3300 Routine Description:
3301
3302 This is the entry called by the I/O system for read requests.
3303 It builds the SRB and sends it to the port driver.
3304
3305 Arguments:
3306
3307 DeviceObject - the system object for the device.
3308 Irp - IRP involved.
3309
3310 Return Value:
3311
3312 NT Status
3313
3314 --*/
3315
3316 {
3317 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
3318 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
3319
3320 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
3321 ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
3322 LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
3323
3324 //PCDROM_DATA cdData = (PCDROM_DATA)(commonExtension->DriverData);
3325
3326 //SCSI_REQUEST_BLOCK srb;
3327 //PCDB cdb = (PCDB)srb.Cdb;
3328 //NTSTATUS status;
3329
3330 PAGED_CODE();
3331
3332 //
3333 // note: we are no longer failing write commands immediately
3334 // they are now failed in StartIo based upon media ability
3335 //
3336
3337 //
3338 // If the cd is playing music then reject this request.
3339 //
3340
3341 if (PLAY_ACTIVE(fdoExtension)) {
3342 Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
3343 return STATUS_DEVICE_BUSY;
3344 }
3345
3346 //
3347 // Verify parameters of this request.
3348 // Check that ending sector is on disc and
3349 // that number of bytes to transfer is a multiple of
3350 // the sector size.
3351 //
3352
3353 startingOffset.QuadPart = currentIrpStack->Parameters.Read.ByteOffset.QuadPart +
3354 transferByteCount;
3355
3356 if (!fdoExtension->DiskGeometry.BytesPerSector) {
3357 fdoExtension->DiskGeometry.BytesPerSector = 2048;
3358 }
3359
3360 if ((startingOffset.QuadPart > commonExtension->PartitionLength.QuadPart) ||
3361 (transferByteCount & (fdoExtension->DiskGeometry.BytesPerSector - 1))) {
3362
3363 //
3364 // Fail request with status of invalid parameters.
3365 //
3366
3367 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
3368
3369 return STATUS_INVALID_PARAMETER;
3370 }
3371
3372
3373 return STATUS_SUCCESS;
3374
3375 } // end CdRomReadWriteVerification()
3376
3377 NTSTATUS
3378 NTAPI
3379 CdRomSwitchModeCompletion(
3380 IN PDEVICE_OBJECT DeviceObject,
3381 IN PIRP Irp,
3382 IN PVOID Context
3383 )
3384 {
3385 PIO_STACK_LOCATION realIrpStack;
3386 PIO_STACK_LOCATION realIrpNextStack;
3387 PIRP realIrp = NULL;
3388 NTSTATUS status;
3389 BOOLEAN retry;
3390 PSCSI_REQUEST_BLOCK srb = Context;
3391 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
3392 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
3393 PCDROM_DATA cdData = (PCDROM_DATA)(commonExtension->DriverData);
3394 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
3395 //BOOLEAN use6Byte = TEST_FLAG(cdData->XAFlags, XA_USE_6_BYTE);
3396 ULONG retryCount;
3397
3398 //
3399 // Extract the 'real' irp from the irpstack.
3400 //
3401
3402 realIrp = (PIRP) irpStack->Parameters.Others.Argument2;
3403 realIrpStack = IoGetCurrentIrpStackLocation(realIrp);
3404 realIrpNextStack = IoGetNextIrpStackLocation(realIrp);
3405
3406 //
3407 // Check SRB status for success of completing request.
3408 //
3409
3410 if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
3411
3412 ULONG retryInterval;
3413
3414 TraceLog((CdromDebugTrace,
3415 "CdRomSetVolumeIntermediateCompletion: Irp %p, Srb %p, Real Irp %p\n",
3416 Irp,
3417 srb,
3418 realIrp));
3419
3420 //
3421 // Release the queue if it is frozen.
3422 //
3423
3424 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
3425 ClassReleaseQueue(DeviceObject);
3426 }
3427
3428
3429 retry = ClassInterpretSenseInfo(DeviceObject,
3430 srb,
3431 irpStack->MajorFunction,
3432 irpStack->Parameters.DeviceIoControl.IoControlCode,
3433 MAXIMUM_RETRIES - ((ULONG)(ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1),
3434 &status,
3435 &retryInterval);
3436
3437 //
3438 // If the status is verified required and the this request
3439 // should bypass verify required then retry the request.
3440 //
3441
3442 if (realIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
3443 status == STATUS_VERIFY_REQUIRED) {
3444
3445 status = STATUS_IO_DEVICE_ERROR;
3446 retry = TRUE;
3447 }
3448
3449 //
3450 // get current retry count
3451 //
3452 retryCount = PtrToUlong(realIrpNextStack->Parameters.Others.Argument1);
3453
3454 if (retry && retryCount) {
3455
3456 //
3457 // decrement retryCount and update
3458 //
3459 realIrpNextStack->Parameters.Others.Argument1 = UlongToPtr(retryCount-1);
3460
3461 if (((ULONG)(ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1)) {
3462
3463 //
3464 // Retry request.
3465 //
3466
3467 TraceLog((CdromDebugWarning,
3468 "Retry request %p - Calling StartIo\n", Irp));
3469
3470
3471 ExFreePool(srb->SenseInfoBuffer);
3472 ExFreePool(srb->DataBuffer);
3473 ExFreePool(srb);
3474 if (Irp->MdlAddress) {
3475 IoFreeMdl(Irp->MdlAddress);
3476 }
3477
3478 IoFreeIrp(Irp);
3479
3480 //
3481 // Call StartIo directly since IoStartNextPacket hasn't been called,
3482 // the serialisation is still intact.
3483 //
3484
3485 CdRomRetryRequest(fdoExtension,
3486 realIrp,
3487 retryInterval,
3488 FALSE);
3489
3490 return STATUS_MORE_PROCESSING_REQUIRED;
3491
3492 }
3493
3494 //
3495 // Exhausted retries. Fall through and complete the request with the appropriate status.
3496 //
3497 }
3498 } else {
3499
3500 //
3501 // Set status for successful request.
3502 //
3503
3504 status = STATUS_SUCCESS;
3505
3506 }
3507
3508 if (NT_SUCCESS(status)) {
3509
3510 ULONG sectorSize, startingSector, transferByteCount;
3511 PCDB cdb;
3512
3513 //
3514 // Update device ext. to show which mode we are currently using.
3515 //
3516
3517 sectorSize = cdData->BlockDescriptor.BlockLength[0] << 16;
3518 sectorSize |= (cdData->BlockDescriptor.BlockLength[1] << 8);
3519 sectorSize |= (cdData->BlockDescriptor.BlockLength[2]);
3520
3521 cdData->RawAccess = (sectorSize == RAW_SECTOR_SIZE) ? TRUE : FALSE;
3522
3523 //
3524 // Free the old data buffer, mdl.
3525 // reuse the SenseInfoBuffer and Srb
3526 //
3527
3528 ExFreePool(srb->DataBuffer);
3529 IoFreeMdl(Irp->MdlAddress);
3530 IoFreeIrp(Irp);
3531
3532 //
3533 // rebuild the srb.
3534 //
3535
3536 cdb = (PCDB)srb->Cdb;
3537 RtlZeroMemory(cdb, CDB12GENERIC_LENGTH);
3538
3539
3540 if (cdData->RawAccess) {
3541
3542 PRAW_READ_INFO rawReadInfo =
3543 (PRAW_READ_INFO)realIrpStack->Parameters.DeviceIoControl.Type3InputBuffer;
3544
3545 ULONG maximumTransferLength;
3546 ULONG transferPages;
3547 //UCHAR min, sec, frame;
3548
3549 //
3550 // Calculate starting offset.
3551 //
3552
3553 startingSector = (ULONG)(rawReadInfo->DiskOffset.QuadPart >> fdoExtension->SectorShift);
3554 transferByteCount = rawReadInfo->SectorCount * RAW_SECTOR_SIZE;
3555 maximumTransferLength = fdoExtension->AdapterDescriptor->MaximumTransferLength;
3556 transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(realIrp->MdlAddress),
3557 transferByteCount);
3558
3559 //
3560 // Determine if request is within limits imposed by miniport.
3561 // If the request is larger than the miniport's capabilities, split it.
3562 //
3563
3564 if (transferByteCount > maximumTransferLength ||
3565 transferPages > fdoExtension->AdapterDescriptor->MaximumPhysicalPages) {
3566
3567
3568 ExFreePool(srb->SenseInfoBuffer);
3569 ExFreePool(srb);
3570 realIrp->IoStatus.Information = 0;
3571 realIrp->IoStatus.Status = STATUS_INVALID_PARAMETER;
3572
3573 BAIL_OUT(realIrp);
3574 CdRomCompleteIrpAndStartNextPacketSafely(DeviceObject, realIrp);
3575 return STATUS_MORE_PROCESSING_REQUIRED;
3576 }
3577
3578 srb->OriginalRequest = realIrp;
3579 srb->SrbFlags = fdoExtension->SrbFlags;
3580 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
3581 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
3582
3583 srb->DataTransferLength = transferByteCount;
3584 srb->TimeOutValue = fdoExtension->TimeOutValue;
3585 srb->CdbLength = 10;
3586 srb->DataBuffer = MmGetMdlVirtualAddress(realIrp->MdlAddress);
3587
3588 if (rawReadInfo->TrackMode == CDDA) {
3589 if (TEST_FLAG(cdData->XAFlags, XA_PLEXTOR_CDDA)) {
3590
3591 srb->CdbLength = 12;
3592
3593 cdb->PLXTR_READ_CDDA.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
3594 cdb->PLXTR_READ_CDDA.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
3595 cdb->PLXTR_READ_CDDA.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
3596 cdb->PLXTR_READ_CDDA.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
3597
3598 cdb->PLXTR_READ_CDDA.TransferBlockByte3 = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
3599 cdb->PLXTR_READ_CDDA.TransferBlockByte2 = (UCHAR) (rawReadInfo->SectorCount >> 8);
3600 cdb->PLXTR_READ_CDDA.TransferBlockByte1 = 0;
3601 cdb->PLXTR_READ_CDDA.TransferBlockByte0 = 0;
3602
3603 cdb->PLXTR_READ_CDDA.SubCode = 0;
3604 cdb->PLXTR_READ_CDDA.OperationCode = 0xD8;
3605
3606 } else if (TEST_FLAG(cdData->XAFlags, XA_NEC_CDDA)) {
3607
3608 cdb->NEC_READ_CDDA.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
3609 cdb->NEC_READ_CDDA.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
3610 cdb->NEC_READ_CDDA.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
3611 cdb->NEC_READ_CDDA.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
3612
3613 cdb->NEC_READ_CDDA.TransferBlockByte1 = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
3614 cdb->NEC_READ_CDDA.TransferBlockByte0 = (UCHAR) (rawReadInfo->SectorCount >> 8);
3615
3616 cdb->NEC_READ_CDDA.OperationCode = 0xD4;
3617 }
3618 } else {
3619 cdb->CDB10.TransferBlocksMsb = (UCHAR) (rawReadInfo->SectorCount >> 8);
3620 cdb->CDB10.TransferBlocksLsb = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
3621
3622 cdb->CDB10.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
3623 cdb->CDB10.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
3624 cdb->CDB10.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
3625 cdb->CDB10.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
3626
3627 cdb->CDB10.OperationCode = SCSIOP_READ;
3628 }
3629
3630 srb->SrbStatus = srb->ScsiStatus = 0;
3631
3632
3633 irpStack = IoGetNextIrpStackLocation(realIrp);
3634 irpStack->MajorFunction = IRP_MJ_SCSI;
3635 irpStack->Parameters.Scsi.Srb = srb;
3636
3637 if (!(irpStack->Parameters.Others.Argument1)) {
3638
3639 //
3640 // Only jam this in if it doesn't exist. The completion routines can
3641 // call StartIo directly in the case of retries and resetting it will
3642 // cause infinite loops.
3643 //
3644
3645 irpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
3646 }
3647
3648 //
3649 // Set up IoCompletion routine address.
3650 //
3651
3652 IoSetCompletionRoutine(realIrp,
3653 CdRomXACompletion,
3654 srb,
3655 TRUE,
3656 TRUE,
3657 TRUE);
3658 } else {
3659
3660 PSTORAGE_ADAPTER_DESCRIPTOR adapterDescriptor;
3661 ULONG maximumTransferLength;
3662 ULONG transferPages;
3663
3664 //
3665 // a writable device must be MMC compliant, which supports
3666 // READ_CD commands, so writes and mode switching should
3667 // never occur on the same device.
3668 //
3669
3670 ASSERT(realIrpStack->MajorFunction != IRP_MJ_WRITE);
3671
3672 //
3673 // free the SRB and SenseInfoBuffer since they aren't used
3674 // by either ClassBuildRequest() nor ClassSplitRequest().
3675 //
3676
3677 ExFreePool(srb->SenseInfoBuffer);
3678 ExFreePool(srb);
3679
3680 //
3681 // Back to cooked sectors. Build and send a normal read.
3682 // The real work for setting offsets was done in startio.
3683 //
3684
3685 adapterDescriptor =
3686 commonExtension->PartitionZeroExtension->AdapterDescriptor;
3687 maximumTransferLength = adapterDescriptor->MaximumTransferLength;
3688 transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
3689 MmGetMdlVirtualAddress(realIrp->MdlAddress),
3690 realIrpStack->Parameters.Read.Length);
3691
3692 if ((realIrpStack->Parameters.Read.Length > maximumTransferLength) ||
3693 (transferPages > adapterDescriptor->MaximumPhysicalPages)) {
3694
3695 ULONG maxPages = adapterDescriptor->MaximumPhysicalPages;
3696
3697 if (maxPages != 0) {
3698 maxPages --; // to account for page boundaries
3699 }
3700
3701 TraceLog((CdromDebugTrace,
3702 "CdromSwitchModeCompletion: Request greater than "
3703 " maximum\n"));
3704 TraceLog((CdromDebugTrace,
3705 "CdromSwitchModeCompletion: Maximum is %lx\n",
3706 maximumTransferLength));
3707 TraceLog((CdromDebugTrace,
3708 "CdromSwitchModeCompletion: Byte count is %lx\n",
3709 realIrpStack->Parameters.Read.Length));
3710
3711 //
3712 // Check that the maximum transfer length fits within
3713 // the maximum number of pages the device can handle.
3714 //
3715
3716 if (maximumTransferLength > maxPages << PAGE_SHIFT) {
3717 maximumTransferLength = maxPages << PAGE_SHIFT;
3718 }
3719
3720 //
3721 // Check that maximum transfer size is not zero
3722 //
3723
3724 if (maximumTransferLength == 0) {
3725 maximumTransferLength = PAGE_SIZE;
3726 }
3727
3728 //
3729 // Request needs to be split. Completion of each portion
3730 // of the request will fire off the next portion. The final
3731 // request will signal Io to send a new request.
3732 //
3733
3734 ClassSplitRequest(DeviceObject, realIrp, maximumTransferLength);
3735 return STATUS_MORE_PROCESSING_REQUIRED;
3736
3737 } else {
3738
3739 //
3740 // Build SRB and CDB for this IRP.
3741 //
3742
3743 ClassBuildRequest(DeviceObject, realIrp);
3744
3745 }
3746 }
3747
3748 //
3749 // Call the port driver.
3750 //
3751
3752 IoCallDriver(commonExtension->LowerDeviceObject, realIrp);
3753
3754 return STATUS_MORE_PROCESSING_REQUIRED;
3755 }
3756
3757 //
3758 // Update device Extension flags to indicate that XA isn't supported.
3759 //
3760
3761 TraceLog((CdromDebugWarning,
3762 "Device Cannot Support CDDA (but tested positive) "
3763 "Now Clearing CDDA flags for FDO %p\n", DeviceObject));
3764 SET_FLAG(cdData->XAFlags, XA_NOT_SUPPORTED);
3765 CLEAR_FLAG(cdData->XAFlags, XA_PLEXTOR_CDDA);
3766 CLEAR_FLAG(cdData->XAFlags, XA_NEC_CDDA);
3767
3768 //
3769 // Deallocate srb and sense buffer.
3770 //
3771
3772 if (srb) {
3773 if (srb->DataBuffer) {
3774 ExFreePool(srb->DataBuffer);
3775 }
3776 if (srb->SenseInfoBuffer) {
3777 ExFreePool(srb->SenseInfoBuffer);
3778 }
3779 ExFreePool(srb);
3780 }
3781
3782 if (Irp->PendingReturned) {
3783 IoMarkIrpPending(Irp);
3784 }
3785
3786 if (realIrp->PendingReturned) {
3787 IoMarkIrpPending(realIrp);
3788 }
3789
3790 if (Irp->MdlAddress) {
3791 IoFreeMdl(Irp->MdlAddress);
3792 }
3793
3794 IoFreeIrp(Irp);
3795
3796 //
3797 // Set status in completing IRP.
3798 //
3799
3800 realIrp->IoStatus.Status = status;
3801
3802 //
3803 // Set the hard error if necessary.
3804 //
3805
3806 if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
3807
3808 //
3809 // Store DeviceObject for filesystem, and clear
3810 // in IoStatus.Information field.
3811 //
3812
3813 if (realIrp->Tail.Overlay.Thread) {
3814 IoSetHardErrorOrVerifyDevice(realIrp, DeviceObject);
3815 }
3816 realIrp->IoStatus.Information = 0;
3817 }
3818
3819 CdRomCompleteIrpAndStartNextPacketSafely(DeviceObject, realIrp);
3820
3821 return STATUS_MORE_PROCESSING_REQUIRED;
3822 }
3823
3824 VOID
3825 NTAPI
3826 ScanForSpecialHandler(
3827 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
3828 ULONG_PTR HackFlags
3829 )
3830 {
3831 PCOMMON_DEVICE_EXTENSION commonExtension;
3832 PCDROM_DATA cdData;
3833
3834 PAGED_CODE();
3835
3836 CLEAR_FLAG(HackFlags, CDROM_HACK_INVALID_FLAGS);
3837
3838 commonExtension = &(FdoExtension->CommonExtension);
3839 cdData = (PCDROM_DATA)(commonExtension->DriverData);
3840 cdData->HackFlags = HackFlags;
3841
3842 return;
3843 }
3844
3845 VOID
3846 NTAPI
3847 ScanForSpecial(
3848 PDEVICE_OBJECT DeviceObject
3849 )
3850
3851 /*++
3852
3853 Routine Description:
3854
3855 This function checks to see if an SCSI logical unit requires an special
3856 initialization or error processing.
3857
3858 Arguments:
3859
3860 DeviceObject - Supplies the device object to be tested.
3861
3862 InquiryData - Supplies the inquiry data returned by the device of interest.
3863
3864 PortCapabilities - Supplies the capabilities of the device object.
3865
3866 Return Value:
3867
3868 None.
3869
3870 --*/
3871
3872 {
3873 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
3874 PCOMMON_DEVICE_EXTENSION commonExtension;
3875 PCDROM_DATA cdData;
3876
3877 PAGED_CODE();
3878
3879 fdoExtension = DeviceObject->DeviceExtension;
3880 commonExtension = DeviceObject->DeviceExtension;
3881 cdData = (PCDROM_DATA)(commonExtension->DriverData);
3882
3883
3884 //
3885 // set our hack flags
3886 //
3887
3888 ClassScanForSpecial(fdoExtension, CdromHackItems, ScanForSpecialHandler);
3889
3890 //
3891 // All CDRom's can ignore the queue lock failure for power operations
3892 // and do not require handling the SpinUp case (unknown result of sending
3893 // a cdrom a START_UNIT command -- may eject disks?)
3894 //
3895 // We send the stop command mostly to stop outstanding asynch operations
3896 // (like audio playback) from running when the system is powered off.
3897 // Because of this and the unlikely chance that a PLAY command will be
3898 // sent in the window between the STOP and the time the machine powers down
3899 // we don't require queue locks. This is important because without them
3900 // classpnp's power routines will send the START_STOP_UNIT command to the
3901 // device whether or not it supports locking (atapi does not support locking
3902 // and if we requested them we would end up not stopping audio on atapi
3903 // devices).
3904 //
3905
3906 SET_FLAG(fdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_DISABLE_SPIN_UP);
3907 SET_FLAG(fdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_NO_QUEUE_LOCK);
3908
3909 if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_HITACHI_1750)
3910 && ( fdoExtension->AdapterDescriptor->AdapterUsesPio )
3911 ) {
3912
3913 //
3914 // Read-ahead must be disabled in order to get this cdrom drive
3915 // to work on scsi adapters that use PIO.
3916 //
3917
3918
3919 TraceLog((CdromDebugWarning,
3920 "CdRom ScanForSpecial: Found Hitachi CDR-1750S.\n"));
3921
3922 //
3923 // Setup an error handler to reinitialize the cd rom after it is reset.
3924 //
3925
3926 cdData->ErrorHandler = HitachiProcessError;
3927
3928 //
3929 // Lock down the hitachi error processing code.
3930 //
3931
3932 MmLockPagableCodeSection(HitachiProcessError);
3933 SET_FLAG(cdData->HackFlags, CDROM_HACK_LOCKED_PAGES);
3934
3935
3936 } else if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_TOSHIBA_SD_W1101)) {
3937
3938 TraceLog((CdromDebugError,
3939 "CdRom ScanForSpecial: Found Toshiba SD-W1101 DVD-RAM "
3940 "-- This drive will *NOT* support DVD-ROM playback.\n"));
3941
3942 } else if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_HITACHI_GD_2000)) {
3943
3944 TraceLog((CdromDebugWarning,
3945 "CdRom ScanForSpecial: Found Hitachi GD-2000\n"));
3946
3947 //
3948 // Setup an error handler to spin up the drive when it idles out
3949 // since it seems to like to fail to spin itself back up on its
3950 // own for a REPORT_KEY command. It may also lose the AGIDs that
3951 // it has given, which will result in DVD playback failures.
3952 // This routine will just do what it can...
3953 //
3954
3955 cdData->ErrorHandler = HitachiProcessErrorGD2000;
3956
3957 //
3958 // this drive may require START_UNIT commands to spin
3959 // the drive up when it's spun itself down.
3960 //
3961
3962 SET_FLAG(fdoExtension->DeviceFlags, DEV_SAFE_START_UNIT);
3963
3964 //
3965 // Lock down the hitachi error processing code.
3966 //
3967
3968 MmLockPagableCodeSection(HitachiProcessErrorGD2000);
3969 SET_FLAG(cdData->HackFlags, CDROM_HACK_LOCKED_PAGES);
3970
3971 } else if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_FUJITSU_FMCD_10x)) {
3972
3973 //
3974 // When Read command is issued to FMCD-101 or FMCD-102 and there is a music
3975 // cd in it. It takes longer time than SCSI_CDROM_TIMEOUT before returning
3976 // error status.
3977 //
3978
3979 fdoExtension->TimeOutValue = 20;
3980
3981 } else if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_DEC_RRD)) {
3982
3983 PMODE_PARM_READ_WRITE_DATA modeParameters;
3984 SCSI_REQUEST_BLOCK srb;
3985 PCDB cdb;
3986 NTSTATUS status;
3987
3988
3989 TraceLog((CdromDebugWarning,
3990 "CdRom ScanForSpecial: Found DEC RRD.\n"));
3991
3992 cdData->IsDecRrd = TRUE;
3993
3994 //
3995 // Setup an error handler to reinitialize the cd rom after it is reset?
3996 //
3997 //commonExtension->DevInfo->ClassError = DecRrdProcessError;
3998
3999 //
4000 // Found a DEC RRD cd-rom. These devices do not pass MS HCT
4001 // multi-media tests because the DEC firmware modifieds the block
4002 // from the PC-standard 2K to 512. Change the block transfer size
4003 // back to the PC-standard 2K by using a mode select command.
4004 //
4005
4006 modeParameters = ExAllocatePoolWithTag(NonPagedPool,
4007 sizeof(MODE_PARM_READ_WRITE_DATA),
4008 CDROM_TAG_MODE_DATA
4009 );
4010 if (modeParameters == NULL) {
4011 return;
4012 }
4013
4014 RtlZeroMemory(modeParameters, sizeof(MODE_PARM_READ_WRITE_DATA));
4015 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
4016
4017 //
4018 // Set the block length to 2K.
4019 //
4020
4021 modeParameters->ParameterListHeader.BlockDescriptorLength =
4022 sizeof(MODE_PARAMETER_BLOCK);
4023
4024 //
4025 // Set block length to 2K (0x0800) in Parameter Block.
4026 //
4027
4028 modeParameters->ParameterListBlock.BlockLength[0] = 0x00; //MSB
4029 modeParameters->ParameterListBlock.BlockLength[1] = 0x08;
4030 modeParameters->ParameterListBlock.BlockLength[2] = 0x00; //LSB
4031
4032 //
4033 // Build the mode select CDB.
4034 //
4035
4036 srb.CdbLength = 6;
4037 srb.TimeOutValue = fdoExtension->TimeOutValue;
4038
4039 cdb = (PCDB)srb.Cdb;
4040 cdb->MODE_SELECT.PFBit = 1;
4041 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
4042 cdb->MODE_SELECT.ParameterListLength = HITACHI_MODE_DATA_SIZE;
4043
4044 //
4045 // Send the request to the device.
4046 //
4047
4048 status = ClassSendSrbSynchronous(DeviceObject,
4049 &srb,
4050 modeParameters,
4051 sizeof(MODE_PARM_READ_WRITE_DATA),
4052 TRUE);
4053
4054 if (!NT_SUCCESS(status)) {
4055 TraceLog((CdromDebugWarning,
4056 "CdRom ScanForSpecial: Setting DEC RRD to 2K block"
4057 "size failed [%x]\n", status));
4058 }
4059 ExFreePool(modeParameters);
4060
4061 } else if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_TOSHIBA_XM_3xx)) {
4062
4063 SCSI_REQUEST_BLOCK srb;
4064 PCDB cdb;
4065 ULONG length;
4066 PUCHAR buffer;
4067 NTSTATUS status;
4068
4069 //
4070 // Set the density code and the error handler.
4071 //
4072
4073 length = (sizeof(MODE_READ_RECOVERY_PAGE) + MODE_BLOCK_DESC_LENGTH + MODE_HEADER_LENGTH);
4074
4075 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
4076
4077 //
4078 // Build the MODE SENSE CDB.
4079 //
4080
4081 srb.CdbLength = 6;
4082 cdb = (PCDB)srb.Cdb;
4083
4084 //
4085 // Set timeout value from device extension.
4086 //
4087
4088 srb.TimeOutValue = fdoExtension->TimeOutValue;
4089
4090 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
4091 cdb->MODE_SENSE.PageCode = 0x1;
4092 // NOTE: purposely not setting DBD because it is what is needed.
4093 cdb->MODE_SENSE.AllocationLength = (UCHAR)length;
4094
4095 buffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
4096 (sizeof(MODE_READ_RECOVERY_PAGE) + MODE_BLOCK_DESC_LENGTH + MODE_HEADER_LENGTH),
4097 CDROM_TAG_MODE_DATA);
4098 if (!buffer) {
4099 return;
4100 }
4101
4102 status = ClassSendSrbSynchronous(DeviceObject,
4103 &srb,
4104 buffer,
4105 length,
4106 FALSE);
4107
4108 ((PERROR_RECOVERY_DATA)buffer)->BlockDescriptor.DensityCode = 0x83;
4109 ((PERROR_RECOVERY_DATA)buffer)->Header.ModeDataLength = 0x0;
4110
4111 RtlCopyMemory(&cdData->Header, buffer, sizeof(ERROR_RECOVERY_DATA));
4112
4113 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
4114
4115 //
4116 // Build the MODE SENSE CDB.
4117 //
4118
4119 srb.CdbLength = 6;
4120 cdb = (PCDB)srb.Cdb;
4121
4122 //
4123 // Set timeout value from device extension.
4124 //
4125
4126 srb.TimeOutValue = fdoExtension->TimeOutValue;
4127
4128 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
4129 cdb->MODE_SELECT.PFBit = 1;
4130 cdb->MODE_SELECT.ParameterListLength = (UCHAR)length;
4131
4132 status = ClassSendSrbSynchronous(DeviceObject,
4133 &srb,
4134 buffer,
4135 length,
4136 TRUE);
4137
4138 if (!NT_SUCCESS(status)) {
4139 TraceLog((CdromDebugWarning,
4140 "Cdrom.ScanForSpecial: Setting density code on Toshiba failed [%x]\n",
4141 status));
4142 }
4143
4144 cdData->ErrorHandler = ToshibaProcessError;
4145
4146 //
4147 // Lock down the toshiba error section.
4148 //
4149
4150 MmLockPagableCodeSection(ToshibaProcessError);
4151 SET_FLAG(cdData->HackFlags, CDROM_HACK_LOCKED_PAGES);
4152
4153 ExFreePool(buffer);
4154
4155 }
4156
4157 //
4158 // Determine special CD-DA requirements.
4159 //
4160
4161 if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_READ_CD_SUPPORTED)) {
4162
4163 SET_FLAG(cdData->XAFlags, XA_USE_READ_CD);
4164
4165 } else if (!TEST_FLAG(cdData->XAFlags, XA_USE_READ_CD)) {
4166
4167 if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_PLEXTOR_CDDA)) {
4168 SET_FLAG(cdData->XAFlags, XA_PLEXTOR_CDDA);
4169 } else if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_NEC_CDDA)) {
4170 SET_FLAG(cdData->XAFlags, XA_NEC_CDDA);
4171 }
4172
4173 }
4174
4175 if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_LOCKED_PAGES)) {
4176 KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_ERROR_LEVEL,
4177 "Locking pages for error handler\n"));
4178 }
4179
4180
4181 return;
4182 }
4183
4184 VOID
4185 NTAPI
4186 HitachiProcessErrorGD2000(
4187 PDEVICE_OBJECT Fdo,
4188 PSCSI_REQUEST_BLOCK OriginalSrb,
4189 NTSTATUS *Status,
4190 BOOLEAN *Retry
4191 )
4192 /*++
4193
4194 Routine Description:
4195
4196 This routine checks the type of error. If the error suggests that the
4197 drive has spun down and cannot reinitialize itself, send a
4198 START_UNIT or READ to the device. This will force the drive to spin
4199 up. This drive also loses the AGIDs it has granted when it spins down,
4200 which may result in playback failure the first time around.
4201
4202 Arguments:
4203
4204 DeviceObject - Supplies a pointer to the device object.
4205
4206 Srb - Supplies a pointer to the failing Srb.
4207
4208 Status - return the final status for this command?
4209
4210 Retry - return if the command should be retried.
4211
4212 Return Value:
4213
4214 None.
4215
4216 --*/
4217 {
4218 PSENSE_DATA senseBuffer = OriginalSrb->SenseInfoBuffer;
4219
4220 UNREFERENCED_PARAMETER(Status);
4221 UNREFERENCED_PARAMETER(Retry);
4222
4223 if (!TEST_FLAG(OriginalSrb->SrbStatus, SRB_STATUS_AUTOSENSE_VALID)) {
4224 return;
4225 }
4226
4227 if (((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_HARDWARE_ERROR) &&
4228 (senseBuffer->AdditionalSenseCode == 0x44)) {
4229
4230 //PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
4231 //PIRP irp;
4232 //PIO_STACK_LOCATION irpStack;
4233 //PCOMPLETION_CONTEXT context;
4234 //PSCSI_REQUEST_BLOCK newSrb;
4235 //PCDB cdb;
4236
4237 TraceLog((CdromDebugWarning,
4238 "HitachiProcessErrorGD2000 (%p) => Internal Target "
4239 "Failure Detected -- spinning up drive\n", Fdo));
4240
4241 //
4242 // the request should be retried because the device isn't ready
4243 //
4244
4245 *Retry = TRUE;
4246 *Status = STATUS_DEVICE_NOT_READY;
4247
4248 //
4249 // send a START_STOP unit to spin up the drive
4250 // NOTE: this temporarily violates the StartIo serialization
4251 // mechanism, but the completion routine on this will NOT
4252 // call StartNextPacket(), so it's a temporary disruption
4253 // of the serialization only.
4254 //
4255
4256 ClassSendStartUnit(Fdo);
4257
4258 }
4259
4260 return;
4261 }
4262
4263 VOID
4264 NTAPI
4265 HitachiProcessError(
4266 PDEVICE_OBJECT DeviceObject,
4267 PSCSI_REQUEST_BLOCK Srb,
4268 NTSTATUS *Status,
4269 BOOLEAN *Retry
4270 )
4271 /*++
4272
4273 Routine Description:
4274
4275 This routine checks the type of error. If the error indicates CD-ROM the
4276 CD-ROM needs to be reinitialized then a Mode sense command is sent to the
4277 device. This command disables read-ahead for the device.
4278
4279 Arguments:
4280
4281 DeviceObject - Supplies a pointer to the device object.
4282
4283 Srb - Supplies a pointer to the failing Srb.
4284
4285 Status - Not used.
4286
4287 Retry - Not used.
4288
4289 Return Value:
4290
4291 None.
4292
4293 --*/
4294
4295 {
4296 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
4297 PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer;
4298 LARGE_INTEGER largeInt;
4299 PUCHAR modePage;
4300 PIO_STACK_LOCATION irpStack;
4301 PIRP irp;
4302 PSCSI_REQUEST_BLOCK srb;
4303 PCOMPLETION_CONTEXT context;
4304 PCDB cdb;
4305 ULONG_PTR alignment;
4306
4307 UNREFERENCED_PARAMETER(Status);
4308 UNREFERENCED_PARAMETER(Retry);
4309
4310 largeInt.QuadPart = (LONGLONG) 1;
4311
4312 //
4313 // Check the status. The initialization command only needs to be sent
4314 // if UNIT ATTENTION is returned.
4315 //
4316
4317 if (!(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID)) {
4318
4319 //
4320 // The drive does not require reinitialization.
4321 //
4322
4323 return;
4324 }
4325
4326 //
4327 // Found an HITACHI cd-rom that does not work with PIO
4328 // adapters when read-ahead is enabled. Read-ahead is disabled by
4329 // a mode select command. The mode select page code is zero and the
4330 // length is 6 bytes. All of the other bytes should be zero.
4331 //
4332
4333 if ((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_UNIT_ATTENTION) {
4334
4335 TraceLog((CdromDebugWarning,
4336 "HitachiProcessError: Reinitializing the CD-ROM.\n"));
4337
4338 //
4339 // Send the special mode select command to disable read-ahead
4340 // on the CD-ROM reader.
4341 //
4342
4343 alignment = DeviceObject->AlignmentRequirement ?
4344 DeviceObject->AlignmentRequirement : 1;
4345
4346 context = ExAllocatePoolWithTag(
4347 NonPagedPool,
4348 sizeof(COMPLETION_CONTEXT) + HITACHI_MODE_DATA_SIZE + (ULONG)alignment,
4349 CDROM_TAG_HITACHI_ERROR
4350 );
4351
4352 if (context == NULL) {
4353
4354 //
4355 // If there is not enough memory to fulfill this request,
4356 // simply return. A subsequent retry will fail and another
4357 // chance to start the unit.
4358 //
4359
4360 return;
4361 }
4362
4363 context->DeviceObject = DeviceObject;
4364 srb = &context->Srb;
4365
4366 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
4367
4368 //
4369 // Write length to SRB.
4370 //
4371
4372 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
4373
4374 //
4375 // Set up SCSI bus address.
4376 //
4377
4378 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
4379 srb->TimeOutValue = fdoExtension->TimeOutValue;
4380
4381 //
4382 // Set the transfer length.
4383 //
4384
4385 srb->DataTransferLength = HITACHI_MODE_DATA_SIZE;
4386 srb->SrbFlags = fdoExtension->SrbFlags;
4387 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_OUT);
4388 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_AUTOSENSE);
4389 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
4390
4391 //
4392 // The data buffer must be aligned.
4393 //
4394
4395 srb->DataBuffer = (PVOID) (((ULONG_PTR) (context + 1) + (alignment - 1)) &
4396 ~(alignment - 1));
4397
4398
4399 //
4400 // Build the HITACHI read-ahead mode select CDB.
4401 //
4402
4403 srb->CdbLength = 6;
4404 cdb = (PCDB)srb->Cdb;
4405 cdb->MODE_SENSE.LogicalUnitNumber = srb->Lun;
4406 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SELECT;
4407 cdb->MODE_SENSE.AllocationLength = HITACHI_MODE_DATA_SIZE;
4408
4409 //
4410 // Initialize the mode sense data.
4411 //
4412
4413 modePage = srb->DataBuffer;
4414
4415 RtlZeroMemory(modePage, HITACHI_MODE_DATA_SIZE);
4416
4417 //
4418 // Set the page length field to 6.
4419 //
4420
4421 modePage[5] = 6;
4422
4423 //
4424 // Build the asynchronous request to be sent to the port driver.
4425 //
4426
4427 irp = IoBuildAsynchronousFsdRequest(IRP_MJ_WRITE,
4428 DeviceObject,
4429 srb->DataBuffer,
4430 srb->DataTransferLength,
4431 &largeInt,
4432 NULL);
4433
4434 if (irp == NULL) {
4435
4436 //
4437 // If there is not enough memory to fulfill this request,
4438 // simply return. A subsequent retry will fail and another
4439 // chance to start the unit.
4440 //
4441
4442 ExFreePool(context);
4443 return;
4444 }
4445
4446 ClassAcquireRemoveLock(DeviceObject, irp);
4447
4448 IoSetCompletionRoutine(irp,
4449 (PIO_COMPLETION_ROUTINE)ClassAsynchronousCompletion,
4450 context,
4451 TRUE,
4452 TRUE,
4453 TRUE);
4454
4455 irpStack = IoGetNextIrpStackLocation(irp);
4456
4457 irpStack->MajorFunction = IRP_MJ_SCSI;
4458
4459 srb->OriginalRequest = irp;
4460
4461 //
4462 // Save SRB address in next stack for port driver.
4463 //
4464
4465 irpStack->Parameters.Scsi.Srb = (PVOID)srb;
4466
4467 //
4468 // Set up IRP Address.
4469 //
4470
4471 (VOID)IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp);
4472
4473 }
4474 }
4475
4476 NTSTATUS
4477 NTAPI
4478 ToshibaProcessErrorCompletion(
4479 PDEVICE_OBJECT DeviceObject,
4480 PIRP Irp,
4481 PVOID Context
4482 )
4483
4484 /*++
4485
4486 Routine Description:
4487
4488 Completion routine for the ClassError routine to handle older Toshiba units
4489 that require setting the density code.
4490
4491 Arguments:
4492
4493 DeviceObject - Supplies a pointer to the device object.
4494
4495 Irp - Pointer to irp created to set the density code.
4496
4497 Context - Supplies a pointer to the Mode Select Srb.
4498
4499
4500 Return Value:
4501
4502 STATUS_MORE_PROCESSING_REQUIRED
4503
4504 --*/
4505
4506 {
4507
4508 PSCSI_REQUEST_BLOCK srb = Context;
4509
4510 //
4511 // Free all of the allocations.
4512 //
4513
4514 ClassReleaseRemoveLock(DeviceObject, Irp);
4515
4516 ExFreePool(srb->DataBuffer);
4517 ExFreePool(srb);
4518 IoFreeMdl(Irp->MdlAddress);
4519 IoFreeIrp(Irp);
4520
4521 //
4522 // Indicate the I/O system should stop processing the Irp completion.
4523 //
4524
4525 return STATUS_MORE_PROCESSING_REQUIRED;
4526 }
4527
4528 VOID
4529 NTAPI
4530 ToshibaProcessError(
4531 PDEVICE_OBJECT DeviceObject,
4532 PSCSI_REQUEST_BLOCK Srb,
4533 NTSTATUS *Status,
4534 BOOLEAN *Retry
4535 )
4536
4537 /*++
4538
4539 Routine Description:
4540
4541 This routine checks the type of error. If the error indicates a unit attention,
4542 the density code needs to be set via a Mode select command.
4543
4544 Arguments:
4545
4546 DeviceObject - Supplies a pointer to the device object.
4547
4548 Srb - Supplies a pointer to the failing Srb.
4549
4550 Status - Not used.
4551
4552 Retry - Not used.
4553
4554 Return Value:
4555
4556 None.
4557
4558 --*/
4559
4560 {
4561 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
4562 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
4563
4564 PCDROM_DATA cdData = (PCDROM_DATA)(commonExtension->DriverData);
4565 PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer;
4566 PIO_STACK_LOCATION irpStack;
4567 PIRP irp;
4568 PSCSI_REQUEST_BLOCK srb;
4569 ULONG length;
4570 PCDB cdb;
4571 PUCHAR dataBuffer;
4572
4573
4574 if (!(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID)) {
4575 return;
4576 }
4577
4578 //
4579 // The Toshiba's require the density code to be set on power up and media changes.
4580 //
4581
4582 if ((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_UNIT_ATTENTION) {
4583
4584
4585 irp = IoAllocateIrp((CCHAR)(DeviceObject->StackSize+1),
4586 FALSE);
4587
4588 if (!irp) {
4589 return;
4590 }
4591
4592 srb = ExAllocatePoolWithTag(NonPagedPool,
4593 sizeof(SCSI_REQUEST_BLOCK),
4594 CDROM_TAG_TOSHIBA_ERROR);
4595 if (!srb) {
4596 IoFreeIrp(irp);
4597 return;
4598 }
4599
4600
4601 length = sizeof(ERROR_RECOVERY_DATA);
4602 dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
4603 length,
4604 CDROM_TAG_TOSHIBA_ERROR);
4605 if (!dataBuffer) {
4606 ExFreePool(srb);
4607 IoFreeIrp(irp);
4608 return;
4609 }
4610
4611 irp->MdlAddress = IoAllocateMdl(dataBuffer,
4612 length,
4613 FALSE,
4614 FALSE,
4615 (PIRP) NULL);
4616
4617 if (!irp->MdlAddress) {
4618 ExFreePool(srb);
4619 ExFreePool(dataBuffer);
4620 IoFreeIrp(irp);
4621 return;
4622 }
4623
4624 //
4625 // Prepare the MDL
4626 //
4627
4628 MmBuildMdlForNonPagedPool(irp->MdlAddress);
4629
4630 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
4631
4632 srb->DataBuffer = dataBuffer;
4633 cdb = (PCDB)srb->Cdb;
4634
4635 //
4636 // Set up the irp.
4637 //
4638
4639 IoSetNextIrpStackLocation(irp);
4640 irp->IoStatus.Status = STATUS_SUCCESS;
4641 irp->IoStatus.Information = 0;
4642 irp->Flags = 0;
4643 irp->UserBuffer = NULL;
4644
4645 //
4646 // Save the device object and irp in a private stack location.
4647 //
4648
4649 irpStack = IoGetCurrentIrpStackLocation(irp);
4650 irpStack->DeviceObject = DeviceObject;
4651
4652 //
4653 // Construct the IRP stack for the lower level driver.
4654 //
4655
4656 irpStack = IoGetNextIrpStackLocation(irp);
4657 irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
4658 irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_OUT;
4659 irpStack->Parameters.Scsi.Srb = srb;
4660
4661 IoSetCompletionRoutine(irp,
4662 ToshibaProcessErrorCompletion,
4663 srb,
4664 TRUE,
4665 TRUE,
4666 TRUE);
4667
4668 ClassAcquireRemoveLock(DeviceObject, irp);
4669
4670 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
4671 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
4672 srb->SrbStatus = srb->ScsiStatus = 0;
4673 srb->NextSrb = 0;
4674 srb->OriginalRequest = irp;
4675 srb->SenseInfoBufferLength = 0;
4676
4677 //
4678 // Set the transfer length.
4679 //
4680
4681 srb->DataTransferLength = length;
4682 srb->SrbFlags = fdoExtension->SrbFlags;
4683 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_OUT);
4684 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_AUTOSENSE);
4685 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
4686 SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE);
4687
4688
4689 srb->CdbLength = 6;
4690 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
4691 cdb->MODE_SELECT.PFBit = 1;
4692 cdb->MODE_SELECT.ParameterListLength = (UCHAR)length;
4693
4694 //
4695 // Copy the Mode page into the databuffer.
4696 //
4697
4698 RtlCopyMemory(srb->DataBuffer, &cdData->Header, length);
4699
4700 //
4701 // Set the density code.
4702 //
4703
4704 ((PERROR_RECOVERY_DATA)srb->DataBuffer)->BlockDescriptor.DensityCode = 0x83;
4705
4706 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp);
4707 }
4708 }
4709
4710 BOOLEAN
4711 NTAPI
4712 CdRomIsPlayActive(
4713 IN PDEVICE_OBJECT DeviceObject
4714 )
4715
4716 /*++
4717
4718 Routine Description:
4719
4720 This routine determines if the cd is currently playing music.
4721
4722 Arguments:
4723
4724 DeviceObject - Device object to test.
4725
4726 Return Value:
4727
4728 TRUE if the device is playing music.
4729
4730 --*/
4731 {
4732 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
4733 IO_STATUS_BLOCK ioStatus;
4734 PSUB_Q_CURRENT_POSITION currentBuffer;
4735
4736 PAGED_CODE();
4737
4738 //
4739 // if we don't think it is playing audio, don't bother checking.
4740 //
4741
4742 if (!PLAY_ACTIVE(fdoExtension)) {
4743 return(FALSE);
4744 }
4745
4746 currentBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
4747 sizeof(SUB_Q_CURRENT_POSITION),
4748 CDROM_TAG_PLAY_ACTIVE);
4749
4750 if (currentBuffer == NULL) {
4751 return(FALSE);
4752 }
4753
4754 ((PCDROM_SUB_Q_DATA_FORMAT) currentBuffer)->Format = IOCTL_CDROM_CURRENT_POSITION;
4755 ((PCDROM_SUB_Q_DATA_FORMAT) currentBuffer)->Track = 0;
4756
4757 //
4758 // Build the synchronous request to be sent to ourself
4759 // to perform the request.
4760 //
4761
4762 ClassSendDeviceIoControlSynchronous(
4763 IOCTL_CDROM_READ_Q_CHANNEL,
4764 DeviceObject,
4765 currentBuffer,
4766 sizeof(CDROM_SUB_Q_DATA_FORMAT),
4767 sizeof(SUB_Q_CURRENT_POSITION),
4768 FALSE,
4769 &ioStatus);
4770
4771 if (!NT_SUCCESS(ioStatus.Status)) {
4772 ExFreePool(currentBuffer);
4773 return FALSE;
4774 }
4775
4776 //
4777 // should update the playactive flag here.
4778 //
4779
4780 if (currentBuffer->Header.AudioStatus == AUDIO_STATUS_IN_PROGRESS) {
4781 PLAY_ACTIVE(fdoExtension) = TRUE;
4782 } else {
4783 PLAY_ACTIVE(fdoExtension) = FALSE;
4784 }
4785
4786 ExFreePool(currentBuffer);
4787
4788 return(PLAY_ACTIVE(fdoExtension));
4789
4790 }
4791
4792 VOID
4793 NTAPI
4794 CdRomTickHandler(
4795 IN PDEVICE_OBJECT DeviceObject
4796 )
4797
4798 /*++
4799
4800 Routine Description:
4801
4802 This routine handles the once per second timer provided by the
4803 Io subsystem. It is used to do delayed retries for cdroms.
4804
4805 Arguments:
4806
4807 DeviceObject - what to check.
4808
4809 Return Value:
4810
4811 None.
4812
4813 --*/
4814
4815 {
4816 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
4817 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
4818
4819 ULONG isRemoved;
4820
4821 KIRQL oldIrql;
4822
4823 //PIRP irp;
4824 //PIRP heldIrpList;
4825 //PIRP nextIrp;
4826 //PLIST_ENTRY listEntry;
4827 PCDROM_DATA cddata;
4828 //PIO_STACK_LOCATION irpStack;
4829 UCHAR uniqueAddress;
4830
4831 isRemoved = ClassAcquireRemoveLock(DeviceObject, (PIRP) &uniqueAddress);
4832
4833 //
4834 // We stop the timer before deleting the device. It's safe to keep going
4835 // if the flag value is REMOVE_PENDING because the removal thread will be
4836 // blocked trying to stop the timer.
4837 //
4838
4839 ASSERT(isRemoved != REMOVE_COMPLETE);
4840
4841 //
4842 // This routine is reasonably safe even if the device object has a pending
4843 // remove
4844
4845 cddata = commonExtension->DriverData;
4846
4847 //
4848 // Since cdrom is completely synchronized there can never be more than one
4849 // irp delayed for retry at any time.
4850 //
4851
4852 KeAcquireSpinLock(&(cddata->DelayedRetrySpinLock), &oldIrql);
4853
4854 if(cddata->DelayedRetryIrp != NULL) {
4855
4856 PIRP irp = cddata->DelayedRetryIrp;
4857
4858 //
4859 // If we've got a delayed retry at this point then there had beter
4860 // be an interval for it.
4861 //
4862
4863 ASSERT(cddata->DelayedRetryInterval != 0);
4864 cddata->DelayedRetryInterval--;
4865
4866 if(isRemoved) {
4867
4868 //
4869 // This device is removed - flush the timer queue
4870 //
4871
4872 cddata->DelayedRetryIrp = NULL;
4873 cddata->DelayedRetryInterval = 0;
4874
4875 KeReleaseSpinLock(&(cddata->DelayedRetrySpinLock), oldIrql);
4876
4877 ClassReleaseRemoveLock(DeviceObject, irp);
4878 ClassCompleteRequest(DeviceObject, irp, IO_CD_ROM_INCREMENT);
4879
4880 } else if (cddata->DelayedRetryInterval == 0) {
4881
4882 //
4883 // Submit this IRP to the lower driver. This IRP does not
4884 // need to be remembered here. It will be handled again when
4885 // it completes.
4886 //
4887
4888 cddata->DelayedRetryIrp = NULL;
4889
4890 KeReleaseSpinLock(&(cddata->DelayedRetrySpinLock), oldIrql);
4891
4892 TraceLog((CdromDebugWarning,
4893 "CdRomTickHandler: Reissuing request %p (thread = %p)\n",
4894 irp,
4895 irp->Tail.Overlay.Thread));
4896
4897 //
4898 // feed this to the appropriate port driver
4899 //
4900
4901 CdRomRerunRequest(fdoExtension, irp, cddata->DelayedRetryResend);
4902 } else {
4903 KeReleaseSpinLock(&(cddata->DelayedRetrySpinLock), oldIrql);
4904 }
4905 } else {
4906 KeReleaseSpinLock(&(cddata->DelayedRetrySpinLock), oldIrql);
4907 }
4908
4909 ClassReleaseRemoveLock(DeviceObject, (PIRP) &uniqueAddress);
4910 }
4911
4912 NTSTATUS
4913 NTAPI
4914 CdRomUpdateGeometryCompletion(
4915 PDEVICE_OBJECT DeviceObject,
4916 PIRP Irp,
4917 PVOID Context
4918 )
4919
4920 /*++
4921
4922 Routine Description:
4923
4924 This routine andles the completion of the test unit ready irps
4925 used to determine if the media has changed. If the media has
4926 changed, this code signals the named event to wake up other
4927 system services that react to media change (aka AutoPlay).
4928
4929 Arguments:
4930
4931 DeviceObject - the object for the completion
4932 Irp - the IRP being completed
4933 Context - the SRB from the IRP
4934
4935 Return Value:
4936
4937 NTSTATUS
4938
4939 --*/
4940
4941 {
4942 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
4943 PCOMMON_DEVICE_EXTENSION commonExtension;
4944
4945 PSCSI_REQUEST_BLOCK srb = (PSCSI_REQUEST_BLOCK) Context;
4946 PREAD_CAPACITY_DATA readCapacityBuffer;
4947 PIO_STACK_LOCATION irpStack;
4948 NTSTATUS status;
4949 BOOLEAN retry;
4950 ULONG retryCount;
4951 //ULONG lastSector;
4952 PIRP originalIrp;
4953 //PCDROM_DATA cddata;
4954 //UCHAR uniqueAddress;
4955
4956 //
4957 // Get items saved in the private IRP stack location.
4958 //
4959
4960 irpStack = IoGetCurrentIrpStackLocation(Irp);
4961 retryCount = (ULONG)(ULONG_PTR) irpStack->Parameters.Others.Argument1;
4962 originalIrp = (PIRP) irpStack->Parameters.Others.Argument2;
4963
4964 if (!DeviceObject) {
4965 DeviceObject = irpStack->DeviceObject;
4966 }
4967 ASSERT(DeviceObject);
4968
4969 fdoExtension = DeviceObject->DeviceExtension;
4970 commonExtension = DeviceObject->DeviceExtension;
4971 //cddata = commonExtension->DriverData;
4972 readCapacityBuffer = srb->DataBuffer;
4973
4974 if ((NT_SUCCESS(Irp->IoStatus.Status)) && (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_SUCCESS)) {
4975
4976 CdRomInterpretReadCapacity(DeviceObject, readCapacityBuffer);
4977
4978 } else {
4979
4980 ULONG retryInterval;
4981
4982 TraceLog((CdromDebugWarning,
4983 "CdRomUpdateGeometryCompletion: [%p] unsuccessful "
4984 "completion of buddy-irp %p (status - %lx)\n",
4985 originalIrp, Irp, Irp->IoStatus.Status));
4986
4987 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
4988 ClassReleaseQueue(DeviceObject);
4989 }
4990
4991 retry = ClassInterpretSenseInfo(DeviceObject,
4992 srb,
4993 IRP_MJ_SCSI,
4994 0,
4995 retryCount,
4996 &status,
4997 &retryInterval);
4998 if (retry) {
4999 retryCount--;
5000 if ((retryCount) && (commonExtension->IsRemoved == NO_REMOVE)) {
5001 PCDB cdb;
5002
5003 TraceLog((CdromDebugWarning,
5004 "CdRomUpdateGeometryCompletion: [%p] Retrying "
5005 "request %p .. thread is %p\n",
5006 originalIrp, Irp, Irp->Tail.Overlay.Thread));
5007
5008 //
5009 // set up a one shot timer to get this process started over
5010 //
5011
5012 irpStack->Parameters.Others.Argument1 = ULongToPtr( retryCount );
5013 irpStack->Parameters.Others.Argument2 = (PVOID) originalIrp;
5014 irpStack->Parameters.Others.Argument3 = (PVOID) 2;
5015
5016 //
5017 // Setup the IRP to be submitted again in the timer routine.
5018 //
5019
5020 irpStack = IoGetNextIrpStackLocation(Irp);
5021 irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
5022 irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
5023 irpStack->Parameters.Scsi.Srb = srb;
5024 IoSetCompletionRoutine(Irp,
5025 CdRomUpdateGeometryCompletion,
5026 srb,
5027 TRUE,
5028 TRUE,
5029 TRUE);
5030
5031 //
5032 // Set up the SRB for read capacity.
5033 //
5034
5035 srb->CdbLength = 10;
5036 srb->TimeOutValue = fdoExtension->TimeOutValue;
5037 srb->SrbStatus = srb->ScsiStatus = 0;
5038 srb->NextSrb = 0;
5039 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
5040 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
5041 srb->SrbFlags = fdoExtension->SrbFlags;
5042 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
5043 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
5044 srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
5045
5046 //
5047 // Set up the CDB
5048 //
5049
5050 cdb = (PCDB) &srb->Cdb[0];
5051 cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
5052
5053 //
5054 // Requests queued onto this list will be sent to the
5055 // lower level driver during CdRomTickHandler
5056 //
5057
5058 CdRomRetryRequest(fdoExtension, Irp, retryInterval, TRUE);
5059
5060 return STATUS_MORE_PROCESSING_REQUIRED;
5061 }
5062
5063 if (commonExtension->IsRemoved != NO_REMOVE) {
5064
5065 //
5066 // We cannot retry the request. Fail it.
5067 //
5068
5069 originalIrp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
5070
5071 } else {
5072
5073 //
5074 // This has been bounced for a number of times. Error the
5075 // original request.
5076 //
5077
5078 originalIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
5079 RtlZeroMemory(&(fdoExtension->DiskGeometry),
5080 sizeof(DISK_GEOMETRY));
5081 fdoExtension->DiskGeometry.BytesPerSector = 2048;
5082 fdoExtension->SectorShift = 11;
5083 commonExtension->PartitionLength.QuadPart =
5084 (LONGLONG)(0x7fffffff);
5085 fdoExtension->DiskGeometry.MediaType = RemovableMedia;
5086 }
5087 } else {
5088
5089 //
5090 // Set up reasonable defaults
5091 //
5092
5093 RtlZeroMemory(&(fdoExtension->DiskGeometry),
5094 sizeof(DISK_GEOMETRY));
5095 fdoExtension->DiskGeometry.BytesPerSector = 2048;
5096 fdoExtension->SectorShift = 11;
5097 commonExtension->PartitionLength.QuadPart = (LONGLONG)(0x7fffffff);
5098 fdoExtension->DiskGeometry.MediaType = RemovableMedia;
5099 }
5100 }
5101
5102 //
5103 // Free resources held.
5104 //
5105
5106 ExFreePool(srb->SenseInfoBuffer);
5107 ExFreePool(srb->DataBuffer);
5108 ExFreePool(srb);
5109 if (Irp->MdlAddress) {
5110 IoFreeMdl(Irp->MdlAddress);
5111 }
5112 IoFreeIrp(Irp);
5113 Irp = NULL;
5114
5115 if (originalIrp->Tail.Overlay.Thread) {
5116
5117 TraceLog((CdromDebugTrace,
5118 "CdRomUpdateGeometryCompletion: [%p] completing "
5119 "original IRP\n", originalIrp));
5120
5121 } else {
5122
5123 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugError,
5124 "CdRomUpdateGeometryCompletion: completing irp %p which has "
5125 "no thread\n", originalIrp));
5126
5127 }
5128
5129 {
5130 // NOTE: should the original irp be sent down to the device object?
5131 // it probably should if the SL_OVERRIDER_VERIFY_VOLUME flag
5132 // is set!
5133 KIRQL oldIrql;
5134 PIO_STACK_LOCATION realIrpStack;
5135
5136 realIrpStack = IoGetCurrentIrpStackLocation(originalIrp);
5137 oldIrql = KeRaiseIrqlToDpcLevel();
5138
5139 if (TEST_FLAG(realIrpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME)) {
5140 CdRomStartIo(DeviceObject, originalIrp);
5141 } else {
5142 originalIrp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
5143 originalIrp->IoStatus.Information = 0;
5144 CdRomCompleteIrpAndStartNextPacketSafely(DeviceObject, originalIrp);
5145 }
5146 KeLowerIrql(oldIrql);
5147 }
5148
5149 return STATUS_MORE_PROCESSING_REQUIRED;
5150 }
5151
5152 NTSTATUS
5153 NTAPI
5154 CdRomUpdateCapacity(
5155 IN PFUNCTIONAL_DEVICE_EXTENSION DeviceExtension,
5156 IN PIRP IrpToComplete,
5157 IN OPTIONAL PKEVENT IoctlEvent
5158 )
5159
5160 /*++
5161
5162 Routine Description:
5163
5164 This routine updates the capacity of the disk as recorded in the device extension.
5165 It also completes the IRP given with STATUS_VERIFY_REQUIRED. This routine is called
5166 when a media change has occurred and it is necessary to determine the capacity of the
5167 new media prior to the next access.
5168
5169 Arguments:
5170
5171 DeviceExtension - the device to update
5172 IrpToComplete - the request that needs to be completed when done.
5173
5174 Return Value:
5175
5176 NTSTATUS
5177
5178 --*/
5179
5180 {
5181 PCOMMON_DEVICE_EXTENSION commonExtension = (PCOMMON_DEVICE_EXTENSION) DeviceExtension;
5182 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION) DeviceExtension;
5183
5184 PCDB cdb;
5185 PIRP irp;
5186 PSCSI_REQUEST_BLOCK srb;
5187 PREAD_CAPACITY_DATA capacityBuffer;
5188 PIO_STACK_LOCATION irpStack;
5189 PUCHAR senseBuffer;
5190 //NTSTATUS status;
5191
5192 irp = IoAllocateIrp((CCHAR)(commonExtension->DeviceObject->StackSize+1),
5193 FALSE);
5194
5195 if (irp) {
5196
5197 srb = ExAllocatePoolWithTag(NonPagedPool,
5198 sizeof(SCSI_REQUEST_BLOCK),
5199 CDROM_TAG_UPDATE_CAP);
5200 if (srb) {
5201 capacityBuffer = ExAllocatePoolWithTag(
5202 NonPagedPoolCacheAligned,
5203 sizeof(READ_CAPACITY_DATA),
5204 CDROM_TAG_UPDATE_CAP);
5205
5206 if (capacityBuffer) {
5207
5208
5209 senseBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
5210 SENSE_BUFFER_SIZE,
5211 CDROM_TAG_UPDATE_CAP);
5212
5213 if (senseBuffer) {
5214
5215 irp->MdlAddress = IoAllocateMdl(capacityBuffer,
5216 sizeof(READ_CAPACITY_DATA),
5217 FALSE,
5218 FALSE,
5219 (PIRP) NULL);
5220
5221 if (irp->MdlAddress) {
5222
5223 //
5224 // Have all resources. Set up the IRP to send for the capacity.
5225 //
5226
5227 IoSetNextIrpStackLocation(irp);
5228 irp->IoStatus.Status = STATUS_SUCCESS;
5229 irp->IoStatus.Information = 0;
5230 irp->Flags = 0;
5231 irp->UserBuffer = NULL;
5232
5233 //
5234 // Save the device object and retry count in a private stack location.
5235 //
5236
5237 irpStack = IoGetCurrentIrpStackLocation(irp);
5238 irpStack->DeviceObject = commonExtension->DeviceObject;
5239 irpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
5240 irpStack->Parameters.Others.Argument2 = (PVOID) IrpToComplete;
5241
5242 //
5243 // Construct the IRP stack for the lower level driver.
5244 //
5245
5246 irpStack = IoGetNextIrpStackLocation(irp);
5247 irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
5248 irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
5249 irpStack->Parameters.Scsi.Srb = srb;
5250 IoSetCompletionRoutine(irp,
5251 CdRomUpdateGeometryCompletion,
5252 srb,
5253 TRUE,
5254 TRUE,
5255 TRUE);
5256 //
5257 // Prepare the MDL
5258 //
5259
5260 MmBuildMdlForNonPagedPool(irp->MdlAddress);
5261
5262
5263 //
5264 // Set up the SRB for read capacity.
5265 //
5266
5267 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
5268 RtlZeroMemory(senseBuffer, SENSE_BUFFER_SIZE);
5269 srb->CdbLength = 10;
5270 srb->TimeOutValue = DeviceExtension->TimeOutValue;
5271 srb->SrbStatus = srb->ScsiStatus = 0;
5272 srb->NextSrb = 0;
5273 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
5274 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
5275 srb->SrbFlags = DeviceExtension->SrbFlags;
5276 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
5277 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
5278 srb->DataBuffer = capacityBuffer;
5279 srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
5280 srb->OriginalRequest = irp;
5281 srb->SenseInfoBuffer = senseBuffer;
5282 srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
5283
5284 //
5285 // Set up the CDB
5286 //
5287
5288 cdb = (PCDB) &srb->Cdb[0];
5289 cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
5290
5291 //
5292 // Set the return value in the IRP that will be completed
5293 // upon completion of the read capacity.
5294 //
5295
5296 IrpToComplete->IoStatus.Status = STATUS_IO_DEVICE_ERROR;
5297 IoMarkIrpPending(IrpToComplete);
5298
5299 IoCallDriver(commonExtension->LowerDeviceObject, irp);
5300
5301 //
5302 // status is not checked because the completion routine for this
5303 // IRP will always get called and it will free the resources.
5304 //
5305
5306 return STATUS_PENDING;
5307
5308 } else {
5309 ExFreePool(senseBuffer);
5310 ExFreePool(capacityBuffer);
5311 ExFreePool(srb);
5312 IoFreeIrp(irp);
5313 }
5314 } else {
5315 ExFreePool(capacityBuffer);
5316 ExFreePool(srb);
5317 IoFreeIrp(irp);
5318 }
5319 } else {
5320 ExFreePool(srb);
5321 IoFreeIrp(irp);
5322 }
5323 } else {
5324 IoFreeIrp(irp);
5325 }
5326 }
5327
5328 //
5329 // complete the original irp with a failure.
5330 // ISSUE-2000/07/05-henrygab - find a way to avoid failure.
5331 //
5332
5333 RtlZeroMemory(&(fdoExtension->DiskGeometry),
5334 sizeof(DISK_GEOMETRY));
5335 fdoExtension->DiskGeometry.BytesPerSector = 2048;
5336 fdoExtension->SectorShift = 11;
5337 commonExtension->PartitionLength.QuadPart =
5338 (LONGLONG)(0x7fffffff);
5339 fdoExtension->DiskGeometry.MediaType = RemovableMedia;
5340
5341 IrpToComplete->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
5342 IrpToComplete->IoStatus.Information = 0;
5343
5344 BAIL_OUT(IrpToComplete);
5345 CdRomCompleteIrpAndStartNextPacketSafely(commonExtension->DeviceObject,
5346 IrpToComplete);
5347 return STATUS_INSUFFICIENT_RESOURCES;
5348 }
5349
5350 NTSTATUS
5351 NTAPI
5352 CdRomRemoveDevice(
5353 IN PDEVICE_OBJECT DeviceObject,
5354 IN UCHAR Type
5355 )
5356
5357 /*++
5358
5359 Routine Description:
5360
5361 This routine is responsible for releasing any resources in use by the
5362 cdrom driver and shutting down it's timer routine. This routine is called
5363 when all outstanding requests have been completed and the device has
5364 disappeared - no requests may be issued to the lower drivers.
5365
5366 Arguments:
5367
5368 DeviceObject - the device object being removed
5369
5370 Return Value:
5371
5372 none - this routine may not fail
5373
5374 --*/
5375
5376 {
5377 PFUNCTIONAL_DEVICE_EXTENSION deviceExtension =
5378 DeviceObject->DeviceExtension;
5379
5380 PCDROM_DATA cdData = deviceExtension->CommonExtension.DriverData;
5381
5382 PAGED_CODE();
5383
5384 if((Type == IRP_MN_QUERY_REMOVE_DEVICE) ||
5385 (Type == IRP_MN_CANCEL_REMOVE_DEVICE)) {
5386 return STATUS_SUCCESS;
5387 }
5388
5389 if(cdData->DelayedRetryIrp != NULL) {
5390 cdData->DelayedRetryInterval = 1;
5391 CdRomTickHandler(DeviceObject);
5392 }
5393
5394 CdRomDeAllocateMmcResources(DeviceObject);
5395
5396 if (deviceExtension->DeviceDescriptor) {
5397 ExFreePool(deviceExtension->DeviceDescriptor);
5398 deviceExtension->DeviceDescriptor = NULL;
5399 }
5400
5401 if (deviceExtension->AdapterDescriptor) {
5402 ExFreePool(deviceExtension->AdapterDescriptor);
5403 deviceExtension->AdapterDescriptor = NULL;
5404 }
5405
5406 if (deviceExtension->SenseData) {
5407 ExFreePool(deviceExtension->SenseData);
5408 deviceExtension->SenseData = NULL;
5409 }
5410
5411 ClassDeleteSrbLookasideList(&deviceExtension->CommonExtension);
5412
5413 if(cdData->CdromInterfaceString.Buffer != NULL) {
5414 IoSetDeviceInterfaceState(
5415 &(cdData->CdromInterfaceString),
5416 FALSE);
5417 RtlFreeUnicodeString(&(cdData->CdromInterfaceString));
5418 RtlInitUnicodeString(&(cdData->CdromInterfaceString), NULL);
5419 }
5420
5421 if(cdData->VolumeInterfaceString.Buffer != NULL) {
5422 IoSetDeviceInterfaceState(
5423 &(cdData->VolumeInterfaceString),
5424 FALSE);
5425 RtlFreeUnicodeString(&(cdData->VolumeInterfaceString));
5426 RtlInitUnicodeString(&(cdData->VolumeInterfaceString), NULL);
5427 }
5428
5429 CdRomDeleteWellKnownName(DeviceObject);
5430
5431 ASSERT(cdData->DelayedRetryIrp == NULL);
5432
5433 if(Type == IRP_MN_REMOVE_DEVICE) {
5434
5435 if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_LOCKED_PAGES)) {
5436
5437 //
5438 // unlock locked pages by locking (to get Mm pointer)
5439 // and then unlocking twice.
5440 //
5441
5442 PVOID locked;
5443
5444 if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_HITACHI_1750)) {
5445
5446 locked = MmLockPagableCodeSection(HitachiProcessError);
5447
5448 } else if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_HITACHI_GD_2000)) {
5449
5450 locked = MmLockPagableCodeSection(HitachiProcessErrorGD2000);
5451
5452 } else if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_TOSHIBA_XM_3xx )) {
5453
5454 locked = MmLockPagableCodeSection(ToshibaProcessError);
5455
5456 } else {
5457
5458 // this is a problem!
5459 // workaround by locking this twice, once for us and
5460 // once for the non-existant locker from ScanForSpecial
5461 ASSERT(!"hack flags show locked section, but none exists?");
5462 locked = MmLockPagableCodeSection(CdRomRemoveDevice);
5463 locked = MmLockPagableCodeSection(CdRomRemoveDevice);
5464
5465
5466 }
5467
5468 MmUnlockPagableImageSection(locked);
5469 MmUnlockPagableImageSection(locked);
5470
5471 }
5472
5473 //
5474 // keep the system-wide count accurate, as
5475 // programs use this info to know when they
5476 // have found all the cdroms in a system.
5477 //
5478
5479 TraceLog((CdromDebugTrace,
5480 "CDROM.SYS Remove device\n"));
5481 IoGetConfigurationInformation()->CdRomCount--;
5482 }
5483
5484 //
5485 // so long, and thanks for all the fish!
5486 //
5487
5488 return STATUS_SUCCESS;
5489 }
5490
5491 DEVICE_TYPE
5492 NTAPI
5493 CdRomGetDeviceType(
5494 IN PDEVICE_OBJECT DeviceObject
5495 )
5496 /*++
5497
5498 Routine Description:
5499
5500 This routine figures out the real device type
5501 by checking CDVD_CAPABILITIES_PAGE
5502
5503 Arguments:
5504
5505 DeviceObject -
5506
5507 Return Value:
5508
5509 FILE_DEVICE_CD_ROM or FILE_DEVICE_DVD
5510
5511
5512 --*/
5513 {
5514 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
5515 PCDROM_DATA cdromExtension;
5516 ULONG bufLength;
5517 SCSI_REQUEST_BLOCK srb;
5518 PCDB cdb;
5519 PMODE_PARAMETER_HEADER10 modePageHeader;
5520 PCDVD_CAPABILITIES_PAGE capPage;
5521 ULONG capPageOffset;
5522 DEVICE_TYPE deviceType;
5523 NTSTATUS status;
5524 BOOLEAN use6Byte;
5525
5526 PAGED_CODE();
5527
5528 //
5529 // NOTE: don't cache this until understand how it affects GetMediaTypes()
5530 //
5531
5532 //
5533 // default device type
5534 //
5535
5536 deviceType = FILE_DEVICE_CD_ROM;
5537
5538 fdoExtension = DeviceObject->DeviceExtension;
5539
5540 cdromExtension = fdoExtension->CommonExtension.DriverData;
5541
5542 use6Byte = TEST_FLAG(cdromExtension->XAFlags, XA_USE_6_BYTE);
5543
5544 RtlZeroMemory(&srb, sizeof(srb));
5545 cdb = (PCDB)srb.Cdb;
5546
5547 //
5548 // Build the MODE SENSE CDB. The data returned will be kept in the
5549 // device extension and used to set block size.
5550 //
5551 if (use6Byte) {
5552
5553 bufLength = sizeof(CDVD_CAPABILITIES_PAGE) +
5554 sizeof(MODE_PARAMETER_HEADER);
5555
5556 capPageOffset = sizeof(MODE_PARAMETER_HEADER);
5557
5558 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
5559 cdb->MODE_SENSE.Dbd = 1;
5560 cdb->MODE_SENSE.PageCode = MODE_PAGE_CAPABILITIES;
5561 cdb->MODE_SENSE.AllocationLength = (UCHAR)bufLength;
5562 srb.CdbLength = 6;
5563 } else {
5564
5565 bufLength = sizeof(CDVD_CAPABILITIES_PAGE) +
5566 sizeof(MODE_PARAMETER_HEADER10);
5567
5568 capPageOffset = sizeof(MODE_PARAMETER_HEADER10);
5569
5570 cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
5571 cdb->MODE_SENSE10.Dbd = 1;
5572 cdb->MODE_SENSE10.PageCode = MODE_PAGE_CAPABILITIES;
5573 cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(bufLength >> 8);
5574 cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(bufLength >> 0);
5575 srb.CdbLength = 10;
5576 }
5577
5578 //
5579 // Set timeout value from device extension.
5580 //
5581 srb.TimeOutValue = fdoExtension->TimeOutValue;
5582
5583 modePageHeader = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
5584 bufLength,
5585 CDROM_TAG_MODE_DATA);
5586 if (modePageHeader) {
5587
5588 RtlZeroMemory(modePageHeader, bufLength);
5589
5590 status = ClassSendSrbSynchronous(
5591 DeviceObject,
5592 &srb,
5593 modePageHeader,
5594 bufLength,
5595 FALSE);
5596
5597 if (NT_SUCCESS(status) ||
5598 (status == STATUS_DATA_OVERRUN) ||
5599 (status == STATUS_BUFFER_OVERFLOW)
5600 ) {
5601
5602 capPage = (PCDVD_CAPABILITIES_PAGE) (((PUCHAR) modePageHeader) + capPageOffset);
5603
5604 if ((capPage->PageCode == MODE_PAGE_CAPABILITIES) &&
5605 (capPage->DVDROMRead || capPage->DVDRRead ||
5606 capPage->DVDRAMRead || capPage->DVDRWrite ||
5607 capPage->DVDRAMWrite)) {
5608
5609 deviceType = FILE_DEVICE_DVD;
5610 }
5611 }
5612 ExFreePool (modePageHeader);
5613 }
5614
5615 return deviceType;
5616 }
5617
5618 NTSTATUS
5619 NTAPI
5620 CdRomCreateWellKnownName(
5621 IN PDEVICE_OBJECT DeviceObject
5622 )
5623 /*++
5624
5625 Routine Description:
5626
5627 This routine creates a symbolic link to the cdrom device object
5628 under \dosdevices. The number of the cdrom device does not necessarily
5629 match between \dosdevices and \device, but usually will be the same.
5630
5631 Saves the buffer
5632
5633 Arguments:
5634
5635 DeviceObject -
5636
5637 Return Value:
5638
5639 NTSTATUS
5640
5641 --*/
5642 {
5643 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
5644 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
5645 PCDROM_DATA cdromData = commonExtension->DriverData;
5646
5647 UNICODE_STRING unicodeLinkName;
5648 WCHAR wideLinkName[64];
5649 PWCHAR savedName;
5650
5651 LONG cdromNumber = fdoExtension->DeviceNumber;
5652
5653 NTSTATUS status;
5654
5655 //
5656 // if already linked, assert then return
5657 //
5658
5659 if (cdromData->WellKnownName.Buffer != NULL) {
5660
5661 TraceLog((CdromDebugError,
5662 "CdRomCreateWellKnownName: link already exists %p\n",
5663 cdromData->WellKnownName.Buffer));
5664 ASSERT(FALSE);
5665 return STATUS_UNSUCCESSFUL;
5666
5667 }
5668
5669 //
5670 // find an unused CdRomNN to link to
5671 //
5672
5673 do {
5674
5675 swprintf(wideLinkName, L"\\DosDevices\\CdRom%d", cdromNumber);
5676 RtlInitUnicodeString(&unicodeLinkName, wideLinkName);
5677 status = IoCreateSymbolicLink(&unicodeLinkName,
5678 &(commonExtension->DeviceName));
5679
5680 cdromNumber++;
5681
5682 } while((status == STATUS_OBJECT_NAME_COLLISION) ||
5683 (status == STATUS_OBJECT_NAME_EXISTS));
5684
5685 if (!NT_SUCCESS(status)) {
5686
5687 TraceLog((CdromDebugWarning,
5688 "CdRomCreateWellKnownName: Error %lx linking %wZ to "
5689 "device %wZ\n",
5690 status,
5691 &unicodeLinkName,
5692 &(commonExtension->DeviceName)));
5693 return status;
5694
5695 }
5696
5697 TraceLog((CdromDebugWarning,
5698 "CdRomCreateWellKnownName: successfully linked %wZ "
5699 "to device %wZ\n",
5700 &unicodeLinkName,
5701 &(commonExtension->DeviceName)));
5702
5703 //
5704 // Save away the symbolic link name in the driver data block. We need
5705 // it so we can delete the link when the device is removed.
5706 //
5707
5708 savedName = ExAllocatePoolWithTag(PagedPool,
5709 unicodeLinkName.MaximumLength,
5710 CDROM_TAG_STRINGS);
5711
5712 if (savedName == NULL) {
5713 IoDeleteSymbolicLink(&unicodeLinkName);
5714 return STATUS_INSUFFICIENT_RESOURCES;
5715 }
5716
5717 RtlCopyMemory(savedName,
5718 unicodeLinkName.Buffer,
5719 unicodeLinkName.MaximumLength);
5720
5721 RtlInitUnicodeString(&(cdromData->WellKnownName), savedName);
5722
5723 //
5724 // the name was saved and the link created
5725 //
5726
5727 return STATUS_SUCCESS;
5728 }
5729
5730 VOID
5731 NTAPI
5732 CdRomDeleteWellKnownName(
5733 IN PDEVICE_OBJECT DeviceObject
5734 )
5735 {
5736 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
5737 PCDROM_DATA cdromData = commonExtension->DriverData;
5738
5739 if(cdromData->WellKnownName.Buffer != NULL) {
5740
5741 IoDeleteSymbolicLink(&(cdromData->WellKnownName));
5742 ExFreePool(cdromData->WellKnownName.Buffer);
5743 cdromData->WellKnownName.Buffer = NULL;
5744 cdromData->WellKnownName.Length = 0;
5745 cdromData->WellKnownName.MaximumLength = 0;
5746
5747 }
5748 return;
5749 }
5750
5751 NTSTATUS
5752 NTAPI
5753 CdRomGetDeviceParameter (
5754 IN PDEVICE_OBJECT Fdo,
5755 IN PWSTR ParameterName,
5756 IN OUT PULONG ParameterValue
5757 )
5758 /*++
5759
5760 Routine Description:
5761
5762 retrieve a devnode registry parameter
5763
5764 Arguments:
5765
5766 DeviceObject - Cdrom Device Object
5767
5768 ParameterName - parameter name to look up
5769
5770 ParameterValue - default parameter value
5771
5772 Return Value:
5773
5774 NT Status
5775
5776 --*/
5777 {
5778 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
5779 NTSTATUS status;
5780 HANDLE deviceParameterHandle;
5781 RTL_QUERY_REGISTRY_TABLE queryTable[2];
5782 ULONG defaultParameterValue;
5783
5784 PAGED_CODE();
5785
5786 //
5787 // open the given parameter
5788 //
5789 status = IoOpenDeviceRegistryKey(fdoExtension->LowerPdo,
5790 PLUGPLAY_REGKEY_DRIVER,
5791 KEY_READ,
5792 &deviceParameterHandle);
5793
5794 if(NT_SUCCESS(status)) {
5795
5796 RtlZeroMemory(queryTable, sizeof(queryTable));
5797
5798 defaultParameterValue = *ParameterValue;
5799
5800 queryTable->Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
5801 queryTable->Name = ParameterName;
5802 queryTable->EntryContext = ParameterValue;
5803 queryTable->DefaultType = REG_NONE;
5804 queryTable->DefaultData = NULL;
5805 queryTable->DefaultLength = 0;
5806
5807 status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
5808 (PWSTR) deviceParameterHandle,
5809 queryTable,
5810 NULL,
5811 NULL);
5812 if (!NT_SUCCESS(status)) {
5813
5814 *ParameterValue = defaultParameterValue;
5815 }
5816
5817 //
5818 // close what we open
5819 //
5820 ZwClose(deviceParameterHandle);
5821 }
5822
5823 return status;
5824
5825 } // CdRomGetDeviceParameter
5826
5827 NTSTATUS
5828 NTAPI
5829 CdRomSetDeviceParameter (
5830 IN PDEVICE_OBJECT Fdo,
5831 IN PWSTR ParameterName,
5832 IN ULONG ParameterValue
5833 )
5834 /*++
5835
5836 Routine Description:
5837
5838 save a devnode registry parameter
5839
5840 Arguments:
5841
5842 DeviceObject - Cdrom Device Object
5843
5844 ParameterName - parameter name
5845
5846 ParameterValue - parameter value
5847
5848 Return Value:
5849
5850 NT Status
5851
5852 --*/
5853 {
5854 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
5855 NTSTATUS status;
5856 HANDLE deviceParameterHandle;
5857
5858 PAGED_CODE();
5859
5860 //
5861 // open the given parameter
5862 //
5863 status = IoOpenDeviceRegistryKey(fdoExtension->LowerPdo,
5864 PLUGPLAY_REGKEY_DRIVER,
5865 KEY_READ | KEY_WRITE,
5866 &deviceParameterHandle);
5867
5868 if(NT_SUCCESS(status)) {
5869
5870 status = RtlWriteRegistryValue(
5871 RTL_REGISTRY_HANDLE,
5872 (PWSTR) deviceParameterHandle,
5873 ParameterName,
5874 REG_DWORD,
5875 &ParameterValue,
5876 sizeof (ParameterValue));
5877
5878 //
5879 // close what we open
5880 //
5881 ZwClose(deviceParameterHandle);
5882 }
5883
5884 return status;
5885
5886 } // CdromSetDeviceParameter
5887
5888 VOID
5889 NTAPI
5890 CdRomPickDvdRegion(
5891 IN PDEVICE_OBJECT Fdo
5892 )
5893 /*++
5894
5895 Routine Description:
5896
5897 pick a default dvd region
5898
5899 Arguments:
5900
5901 DeviceObject - Cdrom Device Object
5902
5903 Return Value:
5904
5905 NT Status
5906
5907 --*/
5908 {
5909 PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
5910 PCDROM_DATA cddata = (PCDROM_DATA)(commonExtension->DriverData);
5911
5912 //
5913 // these five pointers all point to dvdReadStructure or part of
5914 // its data, so don't deallocate them more than once!
5915 //
5916
5917 PDVD_READ_STRUCTURE dvdReadStructure;
5918 PDVD_COPY_PROTECT_KEY copyProtectKey;
5919 PDVD_COPYRIGHT_DESCRIPTOR dvdCopyRight;
5920 PDVD_RPC_KEY rpcKey;
5921 PDVD_SET_RPC_KEY dvdRpcKey;
5922
5923 IO_STATUS_BLOCK ioStatus;
5924 ULONG bufferLen;
5925 UCHAR mediaRegion;
5926 ULONG pickDvdRegion;
5927 ULONG defaultDvdRegion;
5928 ULONG dvdRegion;
5929 ULONG a, b;
5930
5931
5932 PAGED_CODE();
5933
5934 if ((pickDvdRegion = InterlockedExchange(&cddata->PickDvdRegion, 0)) == 0) {
5935
5936 //
5937 // it was non-zero, so either another thread will do this, or
5938 // we no longer need to pick a region
5939 //
5940
5941 return;
5942 }
5943
5944 //
5945 // short-circuit if license agreement violated
5946 //
5947
5948 if (cddata->DvdRpc0LicenseFailure) {
5949 TraceLog((CdromDebugWarning,
5950 "DVD License failure. Refusing to pick a region\n"));
5951 InterlockedExchange(&cddata->PickDvdRegion, 0);
5952 return;
5953 }
5954
5955
5956
5957 a = max(sizeof(DVD_DESCRIPTOR_HEADER) +
5958 sizeof(DVD_COPYRIGHT_DESCRIPTOR),
5959 sizeof(DVD_READ_STRUCTURE)
5960 );
5961 b = max(DVD_RPC_KEY_LENGTH,
5962 DVD_SET_RPC_KEY_LENGTH
5963 );
5964 bufferLen = max(a, b);
5965
5966 dvdReadStructure = (PDVD_READ_STRUCTURE)
5967 ExAllocatePoolWithTag(PagedPool, bufferLen, DVD_TAG_DVD_REGION);
5968
5969 if (dvdReadStructure == NULL) {
5970 InterlockedExchange(&cddata->PickDvdRegion, pickDvdRegion);
5971 return;
5972 }
5973
5974 if (cddata->DvdRpc0Device && cddata->Rpc0RetryRegistryCallback) {
5975
5976 TraceLog((CdromDebugWarning,
5977 "CdRomPickDvdRegion (%p): now retrying RPC0 callback\n",
5978 Fdo));
5979
5980 //
5981 // get the registry settings again
5982 //
5983
5984 ioStatus.Status = CdRomGetRpc0Settings(Fdo);
5985
5986 if (ioStatus.Status == STATUS_LICENSE_VIOLATION) {
5987
5988 //
5989 // if this is the returned error, then
5990 // the routine should have set this!
5991 //
5992
5993 ASSERT(cddata->DvdRpc0LicenseFailure);
5994 cddata->DvdRpc0LicenseFailure = 1;
5995 TraceLog((CdromDebugWarning,
5996 "CdRomPickDvdRegion (%p): "
5997 "setting to fail all dvd ioctls due to CSS licensing "
5998 "failure.\n", Fdo));
5999
6000 pickDvdRegion = 0;
6001 goto getout;
6002
6003 }
6004
6005 //
6006 // get the device region, again
6007 //
6008
6009 copyProtectKey = (PDVD_COPY_PROTECT_KEY)dvdReadStructure;
6010 RtlZeroMemory(copyProtectKey, bufferLen);
6011 copyProtectKey->KeyLength = DVD_RPC_KEY_LENGTH;
6012 copyProtectKey->KeyType = DvdGetRpcKey;
6013
6014 //
6015 // Build a request for READ_KEY
6016 //
6017
6018 ClassSendDeviceIoControlSynchronous(
6019 IOCTL_DVD_READ_KEY,
6020 Fdo,
6021 copyProtectKey,
6022 DVD_RPC_KEY_LENGTH,
6023 DVD_RPC_KEY_LENGTH,
6024 FALSE,
6025 &ioStatus);
6026
6027 if (!NT_SUCCESS(ioStatus.Status)) {
6028 TraceLog((CdromDebugWarning,
6029 "CdRomPickDvdRegion: Unable to get "
6030 "device RPC data (%x)\n", ioStatus.Status));
6031 pickDvdRegion = 0;
6032 goto getout;
6033 }
6034
6035 //
6036 // now that we have gotten the device's RPC data,
6037 // we have set the device extension to usable data.
6038 // no need to call back into this section of code again
6039 //
6040
6041 cddata->Rpc0RetryRegistryCallback = 0;
6042
6043
6044 rpcKey = (PDVD_RPC_KEY) copyProtectKey->KeyData;
6045
6046 //
6047 // TypeCode of zero means that no region has been set.
6048 //
6049
6050 if (rpcKey->TypeCode != 0) {
6051 TraceLog((CdromDebugWarning,
6052 "CdRomPickDvdRegion (%p): DVD Region already "
6053 "chosen\n", Fdo));
6054 pickDvdRegion = 0;
6055 goto getout;
6056 }
6057
6058 TraceLog((CdromDebugWarning,
6059 "CdRomPickDvdRegion (%p): must choose initial DVD "
6060 " Region\n", Fdo));
6061 }
6062
6063
6064
6065 copyProtectKey = (PDVD_COPY_PROTECT_KEY) dvdReadStructure;
6066
6067 dvdCopyRight = (PDVD_COPYRIGHT_DESCRIPTOR)
6068 ((PDVD_DESCRIPTOR_HEADER) dvdReadStructure)->Data;
6069
6070 //
6071 // get the media region
6072 //
6073
6074 RtlZeroMemory (dvdReadStructure, bufferLen);
6075 dvdReadStructure->Format = DvdCopyrightDescriptor;
6076
6077 //
6078 // Build and send a request for READ_KEY
6079 //
6080
6081 TraceLog((CdromDebugTrace,
6082 "CdRomPickDvdRegion (%p): Getting Copyright Descriptor\n",
6083 Fdo));
6084
6085 ClassSendDeviceIoControlSynchronous(
6086 IOCTL_DVD_READ_STRUCTURE,
6087 Fdo,
6088 dvdReadStructure,
6089 sizeof(DVD_READ_STRUCTURE),
6090 sizeof (DVD_DESCRIPTOR_HEADER) +
6091 sizeof(DVD_COPYRIGHT_DESCRIPTOR),
6092 FALSE,
6093 &ioStatus
6094 );
6095 TraceLog((CdromDebugTrace,
6096 "CdRomPickDvdRegion (%p): Got Copyright Descriptor %x\n",
6097 Fdo, ioStatus.Status));
6098
6099 if ((NT_SUCCESS(ioStatus.Status)) &&
6100 (dvdCopyRight->CopyrightProtectionType == 0x01)
6101 ) {
6102
6103 //
6104 // keep the media region bitmap around
6105 // a 1 means ok to play
6106 //
6107
6108 if (dvdCopyRight->RegionManagementInformation == 0xff) {
6109 TraceLog((CdromDebugError,
6110 "CdRomPickDvdRegion (%p): RegionManagementInformation "
6111 "is set to dis-allow playback for all regions. This is "
6112 "most likely a poorly authored disc. defaulting to all "
6113 "region disc for purpose of choosing initial region\n",
6114 Fdo));
6115 dvdCopyRight->RegionManagementInformation = 0;
6116 }
6117
6118
6119 mediaRegion = ~dvdCopyRight->RegionManagementInformation;
6120
6121 } else {
6122
6123 //
6124 // could be media, can't set the device region
6125 //
6126
6127 if (!cddata->DvdRpc0Device) {
6128
6129 //
6130 // can't automatically pick a default region on a rpc2 drive
6131 // without media, so just exit
6132 //
6133 TraceLog((CdromDebugWarning,
6134 "CdRomPickDvdRegion (%p): failed to auto-choose "
6135 "a region due to status %x getting copyright "
6136 "descriptor\n", Fdo, ioStatus.Status));
6137 goto getout;
6138
6139 } else {
6140
6141 //
6142 // for an RPC0 drive, we can try to pick a region for
6143 // the drive
6144 //
6145
6146 mediaRegion = 0x0;
6147 }
6148
6149 }
6150
6151 //
6152 // get the device region
6153 //
6154
6155 RtlZeroMemory (copyProtectKey, bufferLen);
6156 copyProtectKey->KeyLength = DVD_RPC_KEY_LENGTH;
6157 copyProtectKey->KeyType = DvdGetRpcKey;
6158
6159 //
6160 // Build and send a request for READ_KEY for RPC key
6161 //
6162
6163 TraceLog((CdromDebugTrace,
6164 "CdRomPickDvdRegion (%p): Getting RpcKey\n",
6165 Fdo));
6166 ClassSendDeviceIoControlSynchronous(
6167 IOCTL_DVD_READ_KEY,
6168 Fdo,
6169 copyProtectKey,
6170 DVD_RPC_KEY_LENGTH,
6171 DVD_RPC_KEY_LENGTH,
6172 FALSE,
6173 &ioStatus
6174 );
6175 TraceLog((CdromDebugTrace,
6176 "CdRomPickDvdRegion (%p): Got RpcKey %x\n",
6177 Fdo, ioStatus.Status));
6178
6179 if (!NT_SUCCESS(ioStatus.Status)) {
6180
6181 TraceLog((CdromDebugWarning,
6182 "CdRomPickDvdRegion (%p): failed to get RpcKey from "
6183 "a DVD Device\n", Fdo));
6184 goto getout;
6185
6186 }
6187
6188 //
6189 // so we now have what we can get for the media region and the
6190 // drive region. we will not set a region if the drive has one
6191 // set already (mask is not all 1's), nor will we set a region
6192 // if there are no more user resets available.
6193 //
6194
6195 rpcKey = (PDVD_RPC_KEY) copyProtectKey->KeyData;
6196
6197
6198 if (rpcKey->RegionMask != 0xff) {
6199 TraceLog((CdromDebugWarning,
6200 "CdRomPickDvdRegion (%p): not picking a region since "
6201 "it is already chosen\n", Fdo));
6202 goto getout;
6203 }
6204
6205 if (rpcKey->UserResetsAvailable <= 1) {
6206 TraceLog((CdromDebugWarning,
6207 "CdRomPickDvdRegion (%p): not picking a region since "
6208 "only one change remains\n", Fdo));
6209 goto getout;
6210 }
6211
6212 defaultDvdRegion = 0;
6213
6214 //
6215 // the proppage dvd class installer sets
6216 // this key based upon the system locale
6217 //
6218
6219 CdRomGetDeviceParameter (
6220 Fdo,
6221 DVD_DEFAULT_REGION,
6222 &defaultDvdRegion
6223 );
6224
6225 if (defaultDvdRegion > DVD_MAX_REGION) {
6226
6227 //
6228 // the registry has a bogus default
6229 //
6230
6231 TraceLog((CdromDebugWarning,
6232 "CdRomPickDvdRegion (%p): registry has a bogus default "
6233 "region value of %x\n", Fdo, defaultDvdRegion));
6234 defaultDvdRegion = 0;
6235
6236 }
6237
6238 //
6239 // if defaultDvdRegion == 0, it means no default.
6240 //
6241
6242 //
6243 // we will select the initial dvd region for the user
6244 //
6245
6246 if ((defaultDvdRegion != 0) &&
6247 (mediaRegion &
6248 (1 << (defaultDvdRegion - 1))
6249 )
6250 ) {
6251
6252 //
6253 // first choice:
6254 // the media has region that matches
6255 // the default dvd region.
6256 //
6257
6258 dvdRegion = (1 << (defaultDvdRegion - 1));
6259
6260 TraceLog((CdromDebugWarning,
6261 "CdRomPickDvdRegion (%p): Choice #1: media matches "
6262 "drive's default, chose region %x\n", Fdo, dvdRegion));
6263
6264
6265 } else if (mediaRegion) {
6266
6267 //
6268 // second choice:
6269 // pick the lowest region number
6270 // from the media
6271 //
6272
6273 UCHAR mask;
6274
6275 mask = 1;
6276 dvdRegion = 0;
6277 while (mediaRegion && !dvdRegion) {
6278
6279 //
6280 // pick the lowest bit
6281 //
6282 dvdRegion = mediaRegion & mask;
6283 mask <<= 1;
6284 }
6285
6286 TraceLog((CdromDebugWarning,
6287 "CdRomPickDvdRegion (%p): Choice #2: choosing lowest "
6288 "media region %x\n", Fdo, dvdRegion));
6289
6290 } else if (defaultDvdRegion) {
6291
6292 //
6293 // third choice:
6294 // default dvd region from the dvd class installer
6295 //
6296
6297 dvdRegion = (1 << (defaultDvdRegion - 1));
6298 TraceLog((CdromDebugWarning,
6299 "CdRomPickDvdRegion (%p): Choice #3: using default "
6300 "region for this install %x\n", Fdo, dvdRegion));
6301
6302 } else {
6303
6304 //
6305 // unable to pick one for the user -- this should rarely
6306 // happen, since the proppage dvd class installer sets
6307 // the key based upon the system locale
6308 //
6309 TraceLog((CdromDebugWarning,
6310 "CdRomPickDvdRegion (%p): Choice #4: failed to choose "
6311 "a media region\n", Fdo));
6312 goto getout;
6313
6314 }
6315
6316 //
6317 // now that we've chosen a region, set the region by sending the
6318 // appropriate request to the drive
6319 //
6320
6321 RtlZeroMemory (copyProtectKey, bufferLen);
6322 copyProtectKey->KeyLength = DVD_SET_RPC_KEY_LENGTH;
6323 copyProtectKey->KeyType = DvdSetRpcKey;
6324 dvdRpcKey = (PDVD_SET_RPC_KEY) copyProtectKey->KeyData;
6325 dvdRpcKey->PreferredDriveRegionCode = (UCHAR) ~dvdRegion;
6326
6327 //
6328 // Build and send request for SEND_KEY
6329 //
6330 TraceLog((CdromDebugTrace,
6331 "CdRomPickDvdRegion (%p): Sending new Rpc Key to region %x\n",
6332 Fdo, dvdRegion));
6333
6334 ClassSendDeviceIoControlSynchronous(
6335 IOCTL_DVD_SEND_KEY2,
6336 Fdo,
6337 copyProtectKey,
6338 DVD_SET_RPC_KEY_LENGTH,
6339 0,
6340 FALSE,
6341 &ioStatus);
6342 TraceLog((CdromDebugTrace,
6343 "CdRomPickDvdRegion (%p): Sent new Rpc Key %x\n",
6344 Fdo, ioStatus.Status));
6345
6346 if (!NT_SUCCESS(ioStatus.Status)) {
6347 DebugPrint ((1, "CdRomPickDvdRegion (%p): unable to set dvd initial "
6348 " region code (%p)\n", Fdo, ioStatus.Status));
6349 } else {
6350 DebugPrint ((1, "CdRomPickDvdRegion (%p): Successfully set dvd "
6351 "initial region\n", Fdo));
6352 pickDvdRegion = 0;
6353 }
6354
6355 getout:
6356 if (dvdReadStructure) {
6357 ExFreePool (dvdReadStructure);
6358 }
6359
6360 //
6361 // update the new PickDvdRegion value
6362 //
6363
6364 InterlockedExchange(&cddata->PickDvdRegion, pickDvdRegion);
6365
6366 return;
6367 }
6368
6369 NTSTATUS
6370 NTAPI
6371 CdRomRetryRequest(
6372 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
6373 IN PIRP Irp,
6374 IN ULONG Delay,
6375 IN BOOLEAN ResendIrp
6376 )
6377 {
6378 PCDROM_DATA cdData;
6379 KIRQL oldIrql;
6380
6381 if(Delay == 0) {
6382 return CdRomRerunRequest(FdoExtension, Irp, ResendIrp);
6383 }
6384
6385 cdData = FdoExtension->CommonExtension.DriverData;
6386
6387 KeAcquireSpinLock(&(cdData->DelayedRetrySpinLock), &oldIrql);
6388
6389 ASSERT(cdData->DelayedRetryIrp == NULL);
6390 ASSERT(cdData->DelayedRetryInterval == 0);
6391
6392 cdData->DelayedRetryIrp = Irp;
6393 cdData->DelayedRetryInterval = Delay;
6394 cdData->DelayedRetryResend = ResendIrp;
6395
6396 KeReleaseSpinLock(&(cdData->DelayedRetrySpinLock), oldIrql);
6397
6398 return STATUS_PENDING;
6399 }
6400
6401 NTSTATUS
6402 NTAPI
6403 CdRomRerunRequest(
6404 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
6405 IN OPTIONAL PIRP Irp,
6406 IN BOOLEAN ResendIrp
6407 )
6408 {
6409 if(ResendIrp) {
6410 return IoCallDriver(FdoExtension->CommonExtension.LowerDeviceObject,
6411 Irp);
6412 } else {
6413 KIRQL oldIrql;
6414
6415 oldIrql = KeRaiseIrqlToDpcLevel();
6416 CdRomStartIo(FdoExtension->DeviceObject, Irp);
6417 KeLowerIrql(oldIrql);
6418 return STATUS_MORE_PROCESSING_REQUIRED;
6419 }
6420 }
6421
6422 /*++
6423
6424 Routine Description:
6425
6426 This routine just checks for media change sense/asc/ascq and
6427 also for other events, such as bus resets. this is used to
6428 determine if the device behaviour has changed, to allow for
6429 read and write operations to be allowed and/or disallowed.
6430
6431 Arguments:
6432
6433 ISSUE-2000/3/30-henrygab - not fully doc'd
6434
6435 Return Value:
6436
6437 NTSTATUS
6438
6439 --*/
6440
6441 VOID
6442 NTAPI
6443 CdRomMmcErrorHandler(
6444 IN PDEVICE_OBJECT Fdo,
6445 IN PSCSI_REQUEST_BLOCK Srb,
6446 OUT PNTSTATUS Status,
6447 OUT PBOOLEAN Retry
6448 )
6449 {
6450 PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
6451 //BOOLEAN queryCapabilities = FALSE;
6452
6453 if (TEST_FLAG(Srb->SrbStatus, SRB_STATUS_AUTOSENSE_VALID)) {
6454
6455 PCDROM_DATA cddata = (PCDROM_DATA)commonExtension->DriverData;
6456 PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer;
6457
6458 //
6459 // the following sense keys could indicate a change in
6460 // capabilities.
6461 //
6462
6463 //
6464 // we used to expect this to be serialized, and only hit from our
6465 // own routine. we now allow some requests to continue during our
6466 // processing of the capabilities update in order to allow
6467 // IoReadPartitionTable() to succeed.
6468 //
6469
6470 switch (senseBuffer->SenseKey & 0xf) {
6471
6472 case SCSI_SENSE_NOT_READY: {
6473 if (senseBuffer->AdditionalSenseCode ==
6474 SCSI_ADSENSE_NO_MEDIA_IN_DEVICE) {
6475
6476 if (cddata->Mmc.WriteAllowed) {
6477 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
6478 "CdromErrorHandler: media removed, writes will be "
6479 "failed until new media detected\n"));
6480 }
6481
6482 // NOTE - REF #0002
6483 cddata->Mmc.WriteAllowed = FALSE;
6484 } else
6485 if ((senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) &&
6486 (senseBuffer->AdditionalSenseCodeQualifier ==
6487 SCSI_SENSEQ_BECOMING_READY)) {
6488 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
6489 "CdromErrorHandler: media becoming ready, "
6490 "SHOULD notify shell of change time by sending "
6491 "GESN request immediately!\n"));
6492 }
6493 break;
6494 } // end SCSI_SENSE_NOT_READY
6495
6496 case SCSI_SENSE_UNIT_ATTENTION: {
6497 switch (senseBuffer->AdditionalSenseCode) {
6498 case SCSI_ADSENSE_MEDIUM_CHANGED: {
6499
6500 //
6501 // always update if the medium may have changed
6502 //
6503
6504 // NOTE - REF #0002
6505 cddata->Mmc.WriteAllowed = FALSE;
6506 InterlockedCompareExchange(&(cddata->Mmc.UpdateState),
6507 CdromMmcUpdateRequired,
6508 CdromMmcUpdateComplete);
6509
6510 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
6511 "CdromErrorHandler: media change detected, need to "
6512 "update drive capabilities\n"));
6513 break;
6514
6515 } // end SCSI_ADSENSE_MEDIUM_CHANGED
6516
6517 case SCSI_ADSENSE_BUS_RESET: {
6518
6519 // NOTE - REF #0002
6520 cddata->Mmc.WriteAllowed = FALSE;
6521 InterlockedCompareExchange(&(cddata->Mmc.UpdateState),
6522 CdromMmcUpdateRequired,
6523 CdromMmcUpdateComplete);
6524
6525 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
6526 "CdromErrorHandler: bus reset detected, need to "
6527 "update drive capabilities\n"));
6528 break;
6529
6530 } // end SCSI_ADSENSE_BUS_RESET
6531
6532 case SCSI_ADSENSE_OPERATOR_REQUEST: {
6533
6534 BOOLEAN b = FALSE;
6535
6536 switch (senseBuffer->AdditionalSenseCodeQualifier) {
6537 case SCSI_SENSEQ_MEDIUM_REMOVAL: {
6538
6539 //
6540 // eject notification currently handled by classpnp
6541 //
6542
6543 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
6544 "CdromErrorHandler: Eject requested by user\n"));
6545 *Retry = TRUE;
6546 *Status = STATUS_DEVICE_BUSY;
6547 break;
6548 }
6549
6550 case SCSI_SENSEQ_WRITE_PROTECT_DISABLE:
6551 b = TRUE;
6552 case SCSI_SENSEQ_WRITE_PROTECT_ENABLE: {
6553
6554 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
6555 "CdromErrorHandler: Write protect %s requested "
6556 "by user\n",
6557 (b ? "disable" : "enable")));
6558 *Retry = TRUE;
6559 *Status = STATUS_DEVICE_BUSY;
6560 // NOTE - REF #0002
6561 cddata->Mmc.WriteAllowed = FALSE;
6562 InterlockedCompareExchange(&(cddata->Mmc.UpdateState),
6563 CdromMmcUpdateRequired,
6564 CdromMmcUpdateComplete);
6565
6566 }
6567
6568 } // end of AdditionalSenseCodeQualifier switch
6569
6570
6571 break;
6572
6573 } // end SCSI_ADSENSE_OPERATOR_REQUEST
6574
6575 default: {
6576 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
6577 "CdromErrorHandler: Unit attention %02x/%02x\n",
6578 senseBuffer->AdditionalSenseCode,
6579 senseBuffer->AdditionalSenseCodeQualifier));
6580 break;
6581 }
6582
6583 } // end of AdditionSenseCode switch
6584 break;
6585
6586 } // end SCSI_SENSE_UNIT_ATTENTION
6587
6588 case SCSI_SENSE_ILLEGAL_REQUEST: {
6589 if (senseBuffer->AdditionalSenseCode ==
6590 SCSI_ADSENSE_WRITE_PROTECT) {
6591
6592 if (cddata->Mmc.WriteAllowed) {
6593 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
6594 "CdromErrorHandler: media was writable, but "
6595 "failed request with WRITE_PROTECT error...\n"));
6596 }
6597 // NOTE - REF #0002
6598 // do not update all the capabilities just because
6599 // we can't write to the disc.
6600 cddata->Mmc.WriteAllowed = FALSE;
6601 }
6602 break;
6603 } // end SCSI_SENSE_ILLEGAL_REQUEST
6604
6605 } // end of SenseKey switch
6606
6607 } // end of SRB_STATUS_AUTOSENSE_VALID
6608 }
6609
6610 /*++
6611
6612 Routine Description:
6613
6614 This routine checks for a device-specific error handler
6615 and calls it if it exists. This allows multiple drives
6616 that require their own error handler to co-exist.
6617
6618 --*/
6619 VOID
6620 NTAPI
6621 CdRomErrorHandler(
6622 PDEVICE_OBJECT DeviceObject,
6623 PSCSI_REQUEST_BLOCK Srb,
6624 NTSTATUS *Status,
6625 BOOLEAN *Retry
6626 )
6627 {
6628 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
6629 PCDROM_DATA cddata = (PCDROM_DATA)commonExtension->DriverData;
6630 PSENSE_DATA sense = Srb->SenseInfoBuffer;
6631
6632 if ((Srb->SenseInfoBufferLength >=
6633 RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA,AdditionalSenseCodeQualifier)) &&
6634 TEST_FLAG(Srb->SrbStatus, SRB_STATUS_AUTOSENSE_VALID)) {
6635
6636 //
6637 // Many non-WHQL certified drives (mostly CD-RW) return
6638 // 2/4/0 when they have no media instead of the obvious
6639 // choice of:
6640 //
6641 // SCSI_SENSE_NOT_READY/SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
6642 //
6643 // These drives should not pass WHQL certification due
6644 // to this discrepancy.
6645 //
6646 // However, we have to retry on 2/4/0 (Not ready, LUN not ready,
6647 // no info) and also 3/2/0 (no seek complete).
6648 //
6649 // These conditions occur when the shell tries to examine an
6650 // injected CD (e.g. for autoplay) before the CD is spun up.
6651 //
6652 // The drive should be returning an ASCQ of SCSI_SENSEQ_BECOMING_READY
6653 // (0x01) in order to comply with WHQL standards.
6654 //
6655 // The default retry timeout of one second is acceptable to balance
6656 // these discrepancies. don't modify the status, though....
6657 //
6658
6659 if (((sense->SenseKey & 0xf) == SCSI_SENSE_NOT_READY) &&
6660 (sense->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) &&
6661 (sense->AdditionalSenseCodeQualifier == SCSI_SENSEQ_CAUSE_NOT_REPORTABLE)
6662 ) {
6663
6664 *Retry = TRUE;
6665
6666 } else if (((sense->SenseKey & 0xf) == SCSI_SENSE_MEDIUM_ERROR) &&
6667 (sense->AdditionalSenseCode == 0x2) &&
6668 (sense->AdditionalSenseCodeQualifier == 0x0)
6669 ) {
6670
6671 *Retry = TRUE;
6672
6673 } else if ((sense->AdditionalSenseCode == 0x57) &&
6674 (sense->AdditionalSenseCodeQualifier == 0x00)
6675 ) {
6676
6677 //
6678 // UNABLE_TO_RECOVER_TABLE_OF_CONTENTS
6679 // the Matshita CR-585 returns this for all read commands
6680 // on blank CD-R and CD-RW media, and we need to handle
6681 // this for READ_CD detection ability.
6682 //
6683
6684 *Retry = FALSE;
6685 *Status = STATUS_UNRECOGNIZED_MEDIA;
6686
6687 }
6688
6689 }
6690
6691 //
6692 // tail recursion in both cases takes no stack
6693 //
6694
6695 if (cddata->ErrorHandler) {
6696 cddata->ErrorHandler(DeviceObject, Srb, Status, Retry);
6697 }
6698 return;
6699 }
6700
6701 /*++
6702
6703 Routine Description:
6704
6705 This routine is called for a shutdown and flush IRPs.
6706 These are sent by the system before it actually shuts
6707 down or when the file system does a flush.
6708
6709 Arguments:
6710
6711 DriverObject - Pointer to device object to being shutdown by system.
6712
6713 Irp - IRP involved.
6714
6715 Return Value:
6716
6717 NT Status
6718
6719 --*/
6720 NTSTATUS
6721 NTAPI
6722 CdRomShutdownFlush(
6723 IN PDEVICE_OBJECT DeviceObject,
6724 IN PIRP Irp
6725 )
6726 {
6727 IoMarkIrpPending(Irp);
6728 IoStartPacket(DeviceObject, Irp, NULL, NULL);
6729 return STATUS_PENDING;
6730
6731 }
6732
6733 /*++
6734
6735 Routine Description:
6736
6737 This routine is called for intermediate work a shutdown or
6738 flush IRPs would need to do. We just want to free our resources
6739 and return STATUS_MORE_PROCESSING_REQUIRED.
6740
6741 Arguments:
6742
6743 DeviceObject - NULL?
6744
6745 Irp - IRP to free
6746
6747 Context - NULL
6748
6749 Return Value:
6750
6751 NT Status
6752
6753 --*/
6754 NTSTATUS
6755 NTAPI
6756 CdRomShutdownFlushCompletion(
6757 IN PDEVICE_OBJECT Fdo,
6758 IN PIRP NewIrp,
6759 IN PIRP OriginalIrp
6760 )
6761 {
6762 PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
6763 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
6764 PIO_STACK_LOCATION originalIrpStack;
6765 ULONG_PTR iteration;
6766 NTSTATUS status = STATUS_SUCCESS;
6767
6768 ASSERT(OriginalIrp);
6769
6770 originalIrpStack = IoGetCurrentIrpStackLocation(OriginalIrp);
6771
6772 //
6773 // always use a new irp so we can call
6774 // CdRomCompleteIrpAndStartNextPacketSafely() from this routine.
6775 //
6776
6777 if (NewIrp != NULL) {
6778 status = NewIrp->IoStatus.Status;
6779 IoFreeIrp(NewIrp);
6780 NewIrp = NULL;
6781 }
6782
6783 if (!NT_SUCCESS(status)) {
6784 BAIL_OUT(OriginalIrp);
6785 goto SafeExit;
6786 }
6787
6788 //
6789 // the current irpstack saves the counter which states
6790 // what part of the multi-part shutdown or flush we are in.
6791 //
6792
6793 iteration = (ULONG_PTR)originalIrpStack->Parameters.Others.Argument1;
6794 iteration++;
6795 originalIrpStack->Parameters.Others.Argument1 = (PVOID)iteration;
6796
6797 switch (iteration) {
6798 case 2:
6799 if (originalIrpStack->MajorFunction != IRP_MJ_SHUTDOWN) {
6800 //
6801 // then we don't want to send the unlock command
6802 // the incrementing of the state was done above.
6803 // return the completion routine's result.
6804 //
6805 return CdRomShutdownFlushCompletion(Fdo, NULL, OriginalIrp);
6806 }
6807 // else fall through....
6808
6809 case 1: {
6810
6811 PIRP newIrp = NULL;
6812 PSCSI_REQUEST_BLOCK newSrb = NULL;
6813 PCDB newCdb = NULL;
6814 PIO_STACK_LOCATION newIrpStack = NULL;
6815 ULONG isRemoved;
6816
6817 newIrp = IoAllocateIrp((CCHAR)(Fdo->StackSize+1), FALSE);
6818 if (newIrp == NULL) {
6819 BAIL_OUT(OriginalIrp);
6820 status = STATUS_INSUFFICIENT_RESOURCES;
6821 goto SafeExit;
6822 }
6823 newSrb = ExAllocatePoolWithTag(NonPagedPool,
6824 sizeof(SCSI_REQUEST_BLOCK),
6825 CDROM_TAG_SRB);
6826 if (newSrb == NULL) {
6827 IoFreeIrp(newIrp);
6828 BAIL_OUT(OriginalIrp);
6829 status = STATUS_INSUFFICIENT_RESOURCES;
6830 goto SafeExit;
6831 }
6832
6833 //
6834 // ClassIoComplete will free the SRB, but we need a routine
6835 // that will free the irp. then just call ClassSendAsync,
6836 // and don't care about the return value, since the completion
6837 // routine will be called anyways.
6838 //
6839
6840 IoSetNextIrpStackLocation(newIrp);
6841 newIrpStack = IoGetCurrentIrpStackLocation(newIrp);
6842 newIrpStack->DeviceObject = Fdo;
6843 IoSetCompletionRoutine(newIrp,
6844 (PIO_COMPLETION_ROUTINE)CdRomShutdownFlushCompletion,
6845 OriginalIrp,
6846 TRUE, TRUE, TRUE);
6847 IoSetNextIrpStackLocation(newIrp);
6848 newIrpStack = IoGetCurrentIrpStackLocation(newIrp);
6849 newIrpStack->DeviceObject = Fdo;
6850
6851 //
6852 // setup the request
6853 //
6854
6855 RtlZeroMemory(newSrb, sizeof(SCSI_REQUEST_BLOCK));
6856 newCdb = (PCDB)(newSrb->Cdb);
6857
6858 newSrb->QueueTag = SP_UNTAGGED;
6859 newSrb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
6860 newSrb->Function = SRB_FUNCTION_EXECUTE_SCSI;
6861
6862 //
6863 // tell classpnp not to call StartNextPacket()
6864 //
6865
6866 newSrb->SrbFlags = SRB_FLAGS_DONT_START_NEXT_PACKET;
6867
6868 if (iteration == 1) {
6869
6870 //
6871 // first synchronize the cache
6872 //
6873
6874 newSrb->TimeOutValue = fdoExtension->TimeOutValue * 4;
6875 newSrb->CdbLength = 10;
6876 newCdb->SYNCHRONIZE_CACHE10.OperationCode = SCSIOP_SYNCHRONIZE_CACHE;
6877
6878 } else if (iteration == 2) {
6879
6880 //
6881 // then unlock the medium
6882 //
6883
6884 ASSERT( originalIrpStack->MajorFunction == IRP_MJ_SHUTDOWN );
6885
6886 newSrb->TimeOutValue = fdoExtension->TimeOutValue;
6887 newSrb->CdbLength = 6;
6888 newCdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
6889 newCdb->MEDIA_REMOVAL.Prevent = FALSE;
6890
6891 }
6892
6893
6894 isRemoved = ClassAcquireRemoveLock(Fdo, newIrp);
6895 if (isRemoved) {
6896 IoFreeIrp(newIrp);
6897 ExFreePool(newSrb);
6898 ClassReleaseRemoveLock(Fdo, newIrp);
6899 BAIL_OUT(OriginalIrp);
6900 status = STATUS_DEVICE_DOES_NOT_EXIST;
6901 goto SafeExit;
6902 }
6903 ClassSendSrbAsynchronous(Fdo, newSrb, newIrp, NULL, 0, FALSE);
6904 break;
6905 }
6906
6907 case 3: {
6908
6909 PSCSI_REQUEST_BLOCK srb;
6910 PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(OriginalIrp);
6911
6912 //
6913 // forward this request to the device appropriately,
6914 // don't use this completion routine anymore...
6915 //
6916
6917 srb = ExAllocatePoolWithTag(NonPagedPool,
6918 sizeof(SCSI_REQUEST_BLOCK),
6919 CDROM_TAG_SRB);
6920 if (srb == NULL) {
6921 BAIL_OUT(OriginalIrp);
6922 status = STATUS_INSUFFICIENT_RESOURCES;
6923 goto SafeExit;
6924 }
6925
6926 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
6927 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
6928 srb->TimeOutValue = fdoExtension->TimeOutValue * 4;
6929 srb->QueueTag = SP_UNTAGGED;
6930 srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
6931 srb->SrbFlags = fdoExtension->SrbFlags;
6932 srb->CdbLength = 0;
6933 srb->OriginalRequest = OriginalIrp;
6934
6935 if (originalIrpStack->MajorFunction == IRP_MJ_SHUTDOWN) {
6936 srb->Function = SRB_FUNCTION_SHUTDOWN;
6937 } else {
6938 srb->Function = SRB_FUNCTION_FLUSH;
6939 }
6940
6941 //
6942 // Set up IoCompletion routine address.
6943 //
6944
6945 IoSetCompletionRoutine(OriginalIrp,
6946 ClassIoComplete,
6947 srb,
6948 TRUE, TRUE, TRUE);
6949
6950 //
6951 // Set the retry count to zero.
6952 //
6953
6954 originalIrpStack->Parameters.Others.Argument4 = (PVOID) 0;
6955
6956 //
6957 // Get next stack location and set major function code.
6958 //
6959
6960 nextIrpStack->MajorFunction = IRP_MJ_SCSI;
6961
6962 //
6963 // Set up SRB for execute scsi request.
6964 // Save SRB address in next stack for port driver.
6965 //
6966
6967 nextIrpStack->Parameters.Scsi.Srb = srb;
6968
6969 //
6970 // Call the port driver to process the request.
6971 //
6972
6973 IoCallDriver(commonExtension->LowerDeviceObject, OriginalIrp);
6974
6975 break;
6976
6977 }
6978 default: {
6979 ASSERT(FALSE);
6980 break;
6981 }
6982
6983 } // end switch
6984
6985 status = STATUS_SUCCESS;
6986
6987 SafeExit:
6988
6989 if (!NT_SUCCESS(status)) {
6990 OriginalIrp->IoStatus.Status = status;
6991 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, OriginalIrp);
6992 }
6993
6994 //
6995 // always return STATUS_MORE_PROCESSING_REQUIRED, so noone else tries
6996 // to access the new irp that we free'd....
6997 //
6998
6999 return STATUS_MORE_PROCESSING_REQUIRED;
7000
7001 } // end CdromShutdownFlush()
7002
7003 VOID
7004 NTAPI
7005 CdromFakePartitionInfo(
7006 IN PCOMMON_DEVICE_EXTENSION CommonExtension,
7007 IN PIRP Irp
7008 )
7009 {
7010 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
7011 ULONG ioctl = currentIrpStack->Parameters.DeviceIoControl.IoControlCode;
7012 PVOID systemBuffer = Irp->AssociatedIrp.SystemBuffer;
7013
7014 ASSERT(systemBuffer);
7015
7016 if ((ioctl != IOCTL_DISK_GET_DRIVE_LAYOUT) &&
7017 (ioctl != IOCTL_DISK_GET_DRIVE_LAYOUT_EX) &&
7018 (ioctl != IOCTL_DISK_GET_PARTITION_INFO) &&
7019 (ioctl != IOCTL_DISK_GET_PARTITION_INFO_EX)) {
7020 TraceLog((CdromDebugError,
7021 "CdromFakePartitionInfo: unhandled ioctl %x\n", ioctl));
7022 Irp->IoStatus.Status = STATUS_INTERNAL_ERROR;
7023 Irp->IoStatus.Information = 0;
7024 CdRomCompleteIrpAndStartNextPacketSafely(CommonExtension->DeviceObject,
7025 Irp);
7026 return;
7027 }
7028
7029 //
7030 // nothing to fail from this point on, so set the size appropriately
7031 // and set irp's status to success.
7032 //
7033
7034 TraceLog((CdromDebugWarning,
7035 "CdromFakePartitionInfo: incoming ioctl %x\n", ioctl));
7036
7037
7038 Irp->IoStatus.Status = STATUS_SUCCESS;
7039 switch (ioctl) {
7040 case IOCTL_DISK_GET_DRIVE_LAYOUT:
7041 Irp->IoStatus.Information = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION,
7042 PartitionEntry[1]);
7043 RtlZeroMemory(systemBuffer, FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION,
7044 PartitionEntry[1]));
7045 break;
7046 case IOCTL_DISK_GET_DRIVE_LAYOUT_EX:
7047 Irp->IoStatus.Information = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX,
7048 PartitionEntry[1]);
7049 RtlZeroMemory(systemBuffer, FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX,
7050 PartitionEntry[1]));
7051 break;
7052 case IOCTL_DISK_GET_PARTITION_INFO:
7053 Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);
7054 RtlZeroMemory(systemBuffer, sizeof(PARTITION_INFORMATION));
7055 break;
7056 case IOCTL_DISK_GET_PARTITION_INFO_EX:
7057 Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION_EX);
7058 RtlZeroMemory(systemBuffer, sizeof(PARTITION_INFORMATION_EX));
7059 break;
7060 default:
7061 ASSERT(!"Invalid ioctl should not have reached this point\n");
7062 break;
7063 }
7064
7065 //
7066 // if we are getting the drive layout, then we need to start by
7067 // adding some of the non-partition stuff that says we have
7068 // exactly one partition available.
7069 //
7070
7071
7072 if (ioctl == IOCTL_DISK_GET_DRIVE_LAYOUT) {
7073
7074 PDRIVE_LAYOUT_INFORMATION layout;
7075 layout = (PDRIVE_LAYOUT_INFORMATION)systemBuffer;
7076 layout->PartitionCount = 1;
7077 layout->Signature = 1;
7078 systemBuffer = (PVOID)(layout->PartitionEntry);
7079 ioctl = IOCTL_DISK_GET_PARTITION_INFO;
7080
7081 } else if (ioctl == IOCTL_DISK_GET_DRIVE_LAYOUT_EX) {
7082
7083 PDRIVE_LAYOUT_INFORMATION_EX layoutEx;
7084 layoutEx = (PDRIVE_LAYOUT_INFORMATION_EX)systemBuffer;
7085 layoutEx->PartitionStyle = PARTITION_STYLE_MBR;
7086 layoutEx->PartitionCount = 1;
7087 layoutEx->Mbr.Signature = 1;
7088 systemBuffer = (PVOID)(layoutEx->PartitionEntry);
7089 ioctl = IOCTL_DISK_GET_PARTITION_INFO_EX;
7090
7091 }
7092
7093 //
7094 // NOTE: the local var 'ioctl' is now modified to either EX or
7095 // non-EX version. the local var 'systemBuffer' is now pointing
7096 // to the partition information structure.
7097 //
7098
7099 if (ioctl == IOCTL_DISK_GET_PARTITION_INFO) {
7100
7101 PPARTITION_INFORMATION partitionInfo;
7102 partitionInfo = (PPARTITION_INFORMATION)systemBuffer;
7103 partitionInfo->RewritePartition = FALSE;
7104 partitionInfo->RecognizedPartition = TRUE;
7105 partitionInfo->PartitionType = PARTITION_FAT32;
7106 partitionInfo->BootIndicator = FALSE;
7107 partitionInfo->HiddenSectors = 0;
7108 partitionInfo->StartingOffset.QuadPart = 0;
7109 partitionInfo->PartitionLength = CommonExtension->PartitionLength;
7110 partitionInfo->PartitionNumber = 0;
7111
7112 } else {
7113
7114 PPARTITION_INFORMATION_EX partitionInfo;
7115 partitionInfo = (PPARTITION_INFORMATION_EX)systemBuffer;
7116 partitionInfo->PartitionStyle = PARTITION_STYLE_MBR;
7117 partitionInfo->RewritePartition = FALSE;
7118 partitionInfo->Mbr.RecognizedPartition = TRUE;
7119 partitionInfo->Mbr.PartitionType = PARTITION_FAT32;
7120 partitionInfo->Mbr.BootIndicator = FALSE;
7121 partitionInfo->Mbr.HiddenSectors = 0;
7122 partitionInfo->StartingOffset.QuadPart = 0;
7123 partitionInfo->PartitionLength = CommonExtension->PartitionLength;
7124 partitionInfo->PartitionNumber = 0;
7125
7126 }
7127 TraceLog((CdromDebugWarning,
7128 "CdromFakePartitionInfo: finishing ioctl %x\n",
7129 currentIrpStack->Parameters.DeviceIoControl.IoControlCode));
7130
7131 //
7132 // complete the irp
7133 //
7134
7135 CdRomCompleteIrpAndStartNextPacketSafely(CommonExtension->DeviceObject,
7136 Irp);
7137 return;
7138
7139 }