ReactOS  0.4.13-dev-73-gcfe54aa
cdrom.c
Go to the documentation of this file.
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 
66 NTAPI
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 {
92  PCDROM_DRIVER_EXTENSION driverExtension;
94 
95  PAGED_CODE();
96 
98 
100  "CDROM.SYS DriverObject %p loading\n", DriverObject));
101 
104  sizeof(CDROM_DRIVER_EXTENSION),
105  (PVOID*)&driverExtension);
106 
107  if (!NT_SUCCESS(status)) {
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 
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 =
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 
158  InitializationData.ClassUnload = CdRomUnload;
159 
160  //
161  // Call the class init routine
162  //
164 
165 } // end DriverEntry()
166 
167 VOID
168 NTAPI
171  )
172 {
173  PAGED_CODE();
176  "CDROM.SYS DriverObject %p unloading\n", DriverObject));
178  return;
179 } // end CdRomUnload()
180 
181 NTSTATUS
182 NTAPI
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 {
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 
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"));
240 
241  } else {
242 
244  "CDROM.SYS Add failed! %x\n", status));
245 
246  }
247 
248  return status;
249 }
250 
251 NTSTATUS
252 NTAPI
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;
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 
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,
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 
338  ntNameBuffer,
340  TRUE,
341  &deviceObject);
342 
343  if (!NT_SUCCESS(status)) {
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 
406 
407  //
408  // Finally, attach to the PDO
409  //
410 
411  fdoExtension->LowerPdo = PhysicalDeviceObject;
412 
413  fdoExtension->CommonExtension.LowerDeviceObject =
415 
416  if(fdoExtension->CommonExtension.LowerDeviceObject == NULL) {
417 
418  //
419  // Uh - oh, we couldn't attach
420  // cleanup and return
421  //
422 
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)) {
448  "CdromCreateDeviceObjects: unable to create symbolic "
449  "link for device %wZ\n", &fdoExtension->CommonExtension.DeviceName));
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
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
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 
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 
568 
569  //
570  // Allocate request sense buffer.
571  //
572 
576 
577  if (senseData == NULL) {
578 
579  //
580  // The buffer cannot be allocated.
581  //
582 
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 
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 
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 
668  "Checking all profiles for media types supported.\n"
669  ));
670 
671  profileHeader = CdRomFindFeaturePage(cddata->Mmc.CapabilitiesBuffer,
672  cddata->Mmc.CapabilitiesBufferSize,
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  //
683  "CdromDevice supports GET_CONFIGURATION, but "
684  "doesn't provide profiles for PDO %p!\n",
685  fdoExtension->LowerPdo));
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 
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  //
724  "CdromDevice supports GET_CONFIGURATION, but "
725  "doesn't support any of the standard profiles "
726  "for PDO %p!\n", fdoExtension->LowerPdo));
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 
744  cddata->Mmc.CapabilitiesBufferSize,
747  cddata->Mmc.CapabilitiesBufferSize,
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 
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 
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 
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 
805 
806  bps = fdoExtension->DiskGeometry.BytesPerSector;
807 
808  if (!NT_SUCCESS(status) || !bps) {
809 
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 
850  "Detecting XA_READ capabilities\n"));
851 
852  if (CdRomGetDeviceType(Fdo) == FILE_DEVICE_DVD) {
853 
855  "CdRomInitDevice: DVD Devices require START_UNIT\n"));
856 
857 
858  //
859  // all DVD devices must support the READ_CD command
860  //
861 
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 
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 
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 
897 
899  "Forcing detection of READ_CD for FDO %p because "
900  "testing showed some firmware did not properly support it\n",
901  Fdo));
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,
916  &readCdSupported
917  );
918 
919  if (readCdSupported != 0) {
920 
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 
958 
960  length,
962 
963  if (!buffer) {
965  "CdRomDetermineRawReadCapabilities: cannot allocate "
966  "buffer, so leaving for FDO %p\n", Fdo));
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 
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 
1001  &srb,
1002  buffer,
1003  length,
1004  FALSE);
1005 
1006 
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 
1015 
1016  srb.CdbLength = 12;
1017  cdb->READ_CD.OperationCode = SCSIOP_READ_CD;
1018 
1020  &srb,
1021  NULL,
1022  0,
1023  FALSE);
1024 
1025  if (NT_SUCCESS(status) ||
1029  ) {
1030 
1031  //
1032  // READ_CD works
1033  //
1034 
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,
1049  1
1050  );
1051 
1052 
1053  break; // out of the for loop
1054 
1055  }
1056 
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  }
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 
1101  "CdRomDetermineRawReadCapabilities: FDO %p "
1102  "cannot support READ_CD\n", Fdo));
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 
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 
1143  &interfaceName,
1144  TRUE);
1145 
1146  if(!NT_SUCCESS(status)) {
1147 
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 
1161  RtlZeroMemory(&(cddata->Mmc), sizeof(CDROM_MMC_EXTENSION));
1162 
1163  return status;
1164 
1165 }
1166 
1167 NTSTATUS
1168 NTAPI
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 
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 =
1235  bufferLen,
1237 
1238  if (copyProtectKey == NULL) {
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  //
1254  Fdo,
1255  copyProtectKey,
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 
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 
1283  "CdromStartDevice (%p): Delay DVD Region Selection\n",
1284  Fdo));
1285 
1286  cddata->Rpc0SystemRegion = 0xff;
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) {
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
1319  IN UCHAR Type
1320  )
1321 {
1322  return STATUS_SUCCESS;
1323 }
1324 
1325 VOID
1326 NTAPI
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 
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 
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) &&
1369  ) {
1370 
1371  USHORT queueDepth;
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 
1415  (PSLIST_ENTRY)&(Irp->Tail.Overlay.DriverContext[0]), // ReactOS
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,
1431  ASSERT(oldState == CdromMmcUpdateRequired);
1432 
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 
1470  "CdRomStartIo: [%p] Volume needs verified\n", Irp));
1471 
1472  if (!(currentIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME)) {
1473 
1474  if (Irp->Tail.Overlay.Thread) {
1476  }
1477 
1478  Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
1479 
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 
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 
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);
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);
1572  return;
1573  }
1574 
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);
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 
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);
1608  return;
1609  }
1610 
1611  //
1612  // Set up the irp.
1613  //
1614 
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);
1651  irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
1652  irpStack->Parameters.Scsi.Srb = srb;
1653 
1656  srb->SrbStatus = srb->ScsiStatus = 0;
1657  srb->NextSrb = 0;
1658  srb->OriginalRequest = irp2;
1660  srb->SenseInfoBuffer = senseBuffer;
1661 
1662  transferByteCount = (use6Byte) ? sizeof(ERROR_RECOVERY_DATA) : sizeof(ERROR_RECOVERY_DATA10);
1663 
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);
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);
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;
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 
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);
1806  return;
1807  }
1808 
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);
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 
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);
1842  return;
1843  }
1844 
1845  RtlZeroMemory(senseBuffer, SENSE_BUFFER_SIZE);
1846 
1847  //
1848  // Set up the irp.
1849  //
1850 
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);
1894  irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
1895  irpStack->Parameters.Scsi.Srb = srb;
1896 
1899  srb,
1900  TRUE,
1901  TRUE,
1902  TRUE);
1903  //
1904  // Setup those fields that are generic to all requests.
1905  //
1906 
1909  srb->SrbStatus = srb->ScsiStatus = 0;
1910  srb->NextSrb = 0;
1911  srb->OriginalRequest = irp2;
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;
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);
1976  return;
1977 
1978  }
1979 
1980  srb->OriginalRequest = Irp;
1981  srb->SrbFlags = fdoExtension->SrbFlags;
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 
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);
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);
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);
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;
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 
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;
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;
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);
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 
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 
2287 
2288  //
2289  // Issue ReadCapacity to update device extension
2290  // with information for current media.
2291  //
2292 
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;
2304  srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
2305  srb->CdbLength = 10;
2306  srb->TimeOutValue = fdoExtension->TimeOutValue;
2307 
2309  sizeof(READ_CAPACITY_DATA),
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);
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);
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 
2357 
2358  PGET_CONFIGURATION_IOCTL_INPUT inputBuffer;
2359 
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);
2371  return;
2372  }
2373 
2374  transferByteCount = currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
2375 
2377  transferByteCount,
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);
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);
2404  return;
2405  }
2406 
2407  MmBuildMdlForNonPagedPool(irp2->MdlAddress);
2408 
2409  //
2410  // setup remaining srb and cdb parameters
2411  //
2412 
2413  srb->SrbFlags = fdoExtension->SrbFlags;
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;
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);
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 
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;
2525 
2526 
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 
2547  case IOCTL_DVD_READ_KEY: {
2548 
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 
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);
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);
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;
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 
2640  case IOCTL_CDROM_READ_TOC: {
2641 
2642  if (currentIrpStack->Parameters.DeviceIoControl.IoControlCode ==
2644 
2645  //
2646  // Set format to return first and last session numbers.
2647  //
2648 
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;
2681  srb->DataTransferLength = transferByteCount;
2682  srb->CdbLength = 10;
2683  srb->TimeOutValue = fdoExtension->TimeOutValue;
2684 
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);
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);
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 
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;
2757 
2758  IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
2759  return;
2760 
2761  }
2762 
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 
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);
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);
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 
2856  transferByteCount = sizeof(SUB_Q_CURRENT_POSITION);
2857  break;
2858 
2860  transferByteCount = sizeof(SUB_Q_MEDIA_CATALOG_NUMBER);
2861  break;
2862 
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;
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;
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;
2908 
2909  IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
2910  return;
2911  }
2912 
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;
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;
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 
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);
2977  return;
2978 
2979  }
2980 
2981  irp2->MdlAddress = IoAllocateMdl(dataBuffer,
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);
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;
3044  srb->SrbFlags = fdoExtension->SrbFlags;
3047 
3048  IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
3049  return;
3050 
3051  }
3052 
3054  case IOCTL_CDROM_SET_VOLUME: {
3055 
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);
3069  return;
3070  }
3071 
3072  irp2->MdlAddress = IoAllocateMdl(dataBuffer,
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);
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;
3121  srb->SrbFlags = fdoExtension->SrbFlags;
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 
3134  srb,
3135  TRUE,
3136  TRUE,
3137  TRUE);
3138 
3139  }
3140 
3141  IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
3142  return;
3143 
3144  }
3145 
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;
3181 
3182  IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
3183  return;
3184  }
3185 
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 
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  }
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);
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;
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
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 {
3319 
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
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;
3393  PCDROM_DATA cdData = (PCDROM_DATA)(commonExtension->DriverData);
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 
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) {
3426  }
3427 
3428 
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 &&
3444 
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 
3468  "Retry request %p - Calling StartIo\n", Irp));
3469 
3470 
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 
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 
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;
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 
3569  ExFreePool(srb);
3570  realIrp->IoStatus.Information = 0;
3571  realIrp->IoStatus.Status = STATUS_INVALID_PARAMETER;
3572 
3573  BAIL_OUT(realIrp);
3576  }
3577 
3578  srb->OriginalRequest = realIrp;
3579  srb->SrbFlags = fdoExtension->SrbFlags;
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,
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 
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 
3702  "CdromSwitchModeCompletion: Request greater than "
3703  " maximum\n"));
3705  "CdromSwitchModeCompletion: Maximum is %lx\n",
3706  maximumTransferLength));
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);
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 
3755  }
3756 
3757  //
3758  // Update device Extension flags to indicate that XA isn't supported.
3759  //
3760 
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);
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) {
3778  }
3779  ExFreePool(srb);
3780  }
3781 
3782  if (Irp->PendingReturned) {
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 
3807 
3808  //
3809  // Store DeviceObject for filesystem, and clear
3810  // in IoStatus.Information field.
3811  //
3812 
3813  if (realIrp->Tail.Overlay.Thread) {
3815  }
3816  realIrp->IoStatus.Information = 0;
3817  }
3818 
3820 
3822 }
3823 
3824 VOID
3825 NTAPI
3828  ULONG_PTR HackFlags
3829  )
3830 {
3831  PCOMMON_DEVICE_EXTENSION commonExtension;
3832  PCDROM_DATA cdData;
3833 
3834  PAGED_CODE();
3835 
3837 
3838  commonExtension = &(FdoExtension->CommonExtension);
3839  cdData = (PCDROM_DATA)(commonExtension->DriverData);
3840  cdData->HackFlags = HackFlags;
3841 
3842  return;
3843 }
3844 
3845 VOID
3846 NTAPI
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 
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 
3908 
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 
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 
3927 
3928  //
3929  // Lock down the hitachi error processing code.
3930  //
3931 
3934 
3935 
3936  } else if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_TOSHIBA_SD_W1101)) {
3937 
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 
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 
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 
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 
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),
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 
4049  &srb,
4050  modeParameters,
4051  sizeof(MODE_PARM_READ_WRITE_DATA),
4052  TRUE);
4053 
4054  if (!NT_SUCCESS(status)) {
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 
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 
4098  if (!buffer) {
4099  return;
4100  }
4101 
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 
4133  &srb,
4134  buffer,
4135  length,
4136  TRUE);
4137 
4138  if (!NT_SUCCESS(status)) {
4140  "Cdrom.ScanForSpecial: Setting density code on Toshiba failed [%x]\n",
4141  status));
4142  }
4143 
4145 
4146  //
4147  // Lock down the toshiba error section.
4148  //
4149 
4152 
4153  ExFreePool(buffer);
4154 
4155  }
4156 
4157  //
4158  // Determine special CD-DA requirements.
4159  //
4160 
4162 
4163  SET_FLAG(cdData->XAFlags, XA_USE_READ_CD);
4164 
4165  } else if (!TEST_FLAG(cdData->XAFlags, XA_USE_READ_CD)) {
4166 
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 
4177  "Locking pages for error handler\n"));
4178  }
4179 
4180 
4181  return;
4182 }
4183 
4184 VOID
4185 NTAPI
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 
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 
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;
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
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 {
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;
4304  PCDB cdb;
4305  ULONG_PTR alignment;
4306 
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 
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 ?
4345 
4347  NonPagedPool,
4348  sizeof(COMPLETION_CONTEXT) + HITACHI_MODE_DATA_SIZE + (ULONG)alignment,
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 
4367 
4368  //
4369  // Write length to SRB.
4370  //
4371 
4373 
4374  //
4375  // Set up SCSI bus address.
4376  //
4377 
4379  srb->TimeOutValue = fdoExtension->TimeOutValue;
4380 
4381  //
4382  // Set the transfer length.
4383  //
4384 
4386  srb->SrbFlags = fdoExtension->SrbFlags;
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 
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 
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 
4443  return;
4444  }
4445 
4447 
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
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 
4509 
4510  //
4511  // Free all of the allocations.
4512  //
4513 
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 
4526 }
4527 
4528 VOID
4529 NTAPI
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 {
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 
4586  FALSE);
4587 
4588  if (!irp) {
4589  return;
4590  }
4591 
4593  sizeof(SCSI_REQUEST_BLOCK),
4595  if (!srb) {
4596  IoFreeIrp(irp);
4597  return;
4598  }
4599 
4600 
4601  length = sizeof(ERROR_RECOVERY_DATA);
4603  length,
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 
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);
4658  irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_OUT;
4659  irpStack->Parameters.Scsi.Srb = srb;
4660 
4663  srb,
4664  TRUE,
4665  TRUE,
4666  TRUE);
4667 
4669 
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;
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
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 {
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 
4747  sizeof(SUB_Q_CURRENT_POSITION),
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 
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
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 {
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 
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 
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
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 
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  }
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 
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) {
4989  }
4990 
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 
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);
5022  irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
5023  irpStack->Parameters.Scsi.Srb = srb;
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;
5041  srb->SrbFlags = fdoExtension->SrbFlags;
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 
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 
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 
5118  "CdRomUpdateGeometryCompletion: [%p] completing "
5119  "original IRP\n", originalIrp));
5120 
5121  } else {
5122 
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;
5145  }
5146  KeLowerIrql(oldIrql);
5147  }
5148 
5150 }
5151 
5152 NTSTATUS
5153 NTAPI
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 
5198  sizeof(SCSI_REQUEST_BLOCK),
5200  if (srb) {
5201  capacityBuffer = ExAllocatePoolWithTag(
5203  sizeof(READ_CAPACITY_DATA),
5205 
5206  if (capacityBuffer) {
5207 
5208 
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 
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);
5248  irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
5249  irpStack->Parameters.Scsi.Srb = srb;
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;
5275  srb->SrbFlags = DeviceExtension->SrbFlags;
5278  srb->DataBuffer = capacityBuffer;
5279  srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
5280  srb->OriginalRequest = irp;
5281  srb->SenseInfoBuffer = senseBuffer;
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);
5346  IrpToComplete);
5348 }
5349 
5350 NTSTATUS
5351 NTAPI
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 =
5379 
5380  PCDROM_DATA cdData = deviceExtension->CommonExtension.DriverData;
5381 
5382  PAGED_CODE();
5383 
5384  if((Type == IRP_MN_QUERY_REMOVE_DEVICE) ||
5386  return STATUS_SUCCESS;
5387  }
5388 
5389  if(cdData->DelayedRetryIrp != NULL) {
5390  cdData->DelayedRetryInterval = 1;
5392  }
5393 
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) {
5415  &(cdData->CdromInterfaceString),
5416  FALSE);
5419  }
5420 
5421  if(cdData->VolumeInterfaceString.Buffer != NULL) {
5423  &(cdData->VolumeInterfaceString),
5424  FALSE);
5427  }
5428 
5430 
5431  ASSERT(cdData->DelayedRetryIrp == NULL);
5432 
5433  if(Type == IRP_MN_REMOVE_DEVICE) {
5434 
5436 
5437  //
5438  // unlock locked pages by locking (to get Mm pointer)
5439  // and then unlocking twice.
5440  //
5441 
5442  PVOID locked;
5443 
5445 
5447 
5448  } else if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_HITACHI_GD_2000)) {
5449 
5451 
5452  } else if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_TOSHIBA_XM_3xx )) {
5453 
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?");
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 
5480  "CDROM.SYS Remove device\n"));
5482  }
5483 
5484  //
5485  // so long, and thanks for all the fish!
5486  //
5487 
5488  return STATUS_SUCCESS;
5489 }
5490 
5492 NTAPI
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