ReactOS  0.4.15-dev-2738-gbe65a85
init.c
Go to the documentation of this file.
1 /*--
2 
3 Copyright (C) Microsoft Corporation. All rights reserved.
4 
5 Module Name:
6 
7  init.c
8 
9 Abstract:
10 
11  Initialization routines for CDROM
12 
13 Environment:
14 
15  kernel mode only
16 
17 Notes:
18 
19 
20 Revision History:
21 
22 --*/
23 
24 
25 #include "ntddk.h"
26 #include "ntddstor.h"
27 #include "ntstrsafe.h"
28 #include "devpkey.h"
29 
30 #include "cdrom.h"
31 #include "scratch.h"
32 #include "mmc.h"
33 
34 #ifdef DEBUG_USE_WPP
35 #include "init.tmh"
36 #endif
37 
40 DeviceInitAllocateBuffers(
41  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
42  );
43 
46 DeviceRetrieveScsiAddress(
47  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
48  _In_ PSCSI_ADDRESS ScsiAddress
49  );
50 
53 DeviceRetrieveDescriptorsAndTransferLength(
54  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
55  );
56 
58 VOID
59 DeviceScanSpecialDevices(
60  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
61  );
62 
65 DeviceInitMmcContext(
66  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
67  );
68 
71 DeviceGetMmcSupportInfo(
72  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
73  _Out_ PBOOLEAN IsMmcDevice
74  );
75 
76 #if (NTDDI_VERSION >= NTDDI_WIN8)
79 DeviceIsPortable(
80  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
81  _Out_ PBOOLEAN IsPortable
82  );
83 #endif
84 
85 
86 #ifdef ALLOC_PRAGMA
87 
88 #pragma alloc_text(PAGE, DeviceClaimRelease)
89 #pragma alloc_text(PAGE, DeviceEvtSelfManagedIoInit)
90 
91 #pragma alloc_text(PAGE, DeviceInitReleaseQueueContext)
92 #pragma alloc_text(PAGE, DeviceInitAllocateBuffers)
93 #pragma alloc_text(PAGE, DeviceInitPowerContext)
94 #pragma alloc_text(PAGE, DeviceCreateWellKnownName)
95 #pragma alloc_text(PAGE, DeviceRetrieveScsiAddress)
96 #pragma alloc_text(PAGE, DeviceRetrieveDescriptorsAndTransferLength)
97 #pragma alloc_text(PAGE, DeviceInitializeHotplugInfo)
98 #pragma alloc_text(PAGE, DeviceScanSpecialDevices)
99 #pragma alloc_text(PAGE, DeviceGetTimeOutValueFromRegistry)
100 #pragma alloc_text(PAGE, DeviceGetMmcSupportInfo)
101 #pragma alloc_text(PAGE, DeviceRetrieveDescriptor)
102 #pragma alloc_text(PAGE, DeviceRetrieveHackFlagsFromRegistry)
103 #pragma alloc_text(PAGE, DeviceScanForSpecial)
104 #pragma alloc_text(PAGE, DeviceHackFlagsScan)
105 #pragma alloc_text(PAGE, DeviceInitMmcContext)
106 #pragma alloc_text(PAGE, ScanForSpecialHandler)
107 #pragma alloc_text(PAGE, DeviceSetRawReadInfo)
108 #pragma alloc_text(PAGE, DeviceInitializeDvd)
109 #pragma alloc_text(PAGE, DeviceCacheDeviceInquiryData)
110 
111 #if (NTDDI_VERSION >= NTDDI_WIN8)
112 #pragma alloc_text(PAGE, DeviceIsPortable)
113 #endif
114 
115 #endif
116 
117 #pragma warning(push)
118 #pragma warning(disable:4152) // nonstandard extension, function/data pointer conversion in expression
119 #pragma warning(disable:26000) // read overflow reported because of pointer type conversion
120 
122 NTSTATUS
123 DeviceClaimRelease(
124  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
126  )
127 /*++
128 
129 Routine Description:
130 
131  This function claims a device in the port driver. The port driver object
132  is updated with the correct driver object if the device is successfully
133  claimed.
134 
135 Arguments:
136 
137  Device - The WDFDEVICE that needs to be claimed or released.
138 
139  Release - Indicates the logical unit should be released rather than claimed.
140 
141 Return Value:
142 
143  Returns a status indicating success or failure of the operation.
144 
145 --*/
146 {
148  SCSI_REQUEST_BLOCK srb = {0};
150  WDFREQUEST request;
151  WDF_OBJECT_ATTRIBUTES attributes;
152 
153  PAGED_CODE();
154 
155  //Create a request
158 
159  status = WdfRequestCreate(&attributes,
160  DeviceExtension->IoTarget,
161  &request);
162 
163  if (NT_SUCCESS(status))
164  {
165  //fill up srb structure
166  srb.OriginalRequest = WdfRequestWdmGetIrp(request);
168 
169  srb.Length = sizeof(SCSI_REQUEST_BLOCK);
170 
171  srb.Function = Release
174 
175 
177  &srb,
178  sizeof(srb));
179 
180  status = WdfIoTargetSendInternalIoctlOthersSynchronously(DeviceExtension->IoTarget,
181  request,
183  &descriptor,
184  NULL,
185  NULL,
186  NULL,
187  NULL);
188 
190 
191  // The request should be deleted.
192  WdfObjectDelete(request);
193 
194  if (!NT_SUCCESS(status))
195  {
196  TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP,
197  "DeviceClaimRelease: Failed to %s device, status: 0x%X\n",
198  Release ? "Release" : "Claim",
199  status));
200  }
201  }
202  else
203  {
204  TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP,
205  "DeviceClaimRelease: Failed to create request, status: 0x%X\n",
206  status));
207  }
208 
209  if (Release)
210  {
211  // We only release the device when we don't want to manage it.
212  // The failure status does not matter.
214  }
215 
216  return status;
217 } // end DeviceClaimRelease()
218 
219 
220 NTSTATUS
221 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
223  _In_ WDFDEVICE Device
224  )
225 /*++
226 
227 Routine Description:
228 
229  This routine is called only once after the device is added in system, so it's used to do
230  hardware-dependent device initialization work and resource allocation.
231  If this routine fails, DeviceEvtSelfManagedIoCleanup will be invoked by the framework.
232 
233 Arguments:
234 
235  Device - Handle to device object
236 
237 Return Value:
238 
239  NTSTATUS
240 
241 --*/
242 {
244  PCDROM_DEVICE_EXTENSION deviceExtension = NULL;
245 
246  PAGED_CODE();
247 
248  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP,
249  "DeviceEvtSelfManagedIoInit: WDFDEVICE %p is being started.\n",
250  Device));
251 
252  deviceExtension = DeviceGetExtension(Device);
253 
254  // 1. Set/retrieve basic information, some of the following operations may depend on it
255  if (NT_SUCCESS(status))
256  {
257  // We do not care if this function fails, SCSI address is mainly for debugging/tracing purposes.
258  (VOID) DeviceRetrieveScsiAddress(deviceExtension, &deviceExtension->ScsiAddress);
259  }
260 
261  if (NT_SUCCESS(status))
262  {
263  status = DeviceRetrieveDescriptorsAndTransferLength(deviceExtension);
264  }
265 
266  if (NT_SUCCESS(status))
267  {
268  // This function should be called after DeviceRetrieveDescriptorsAndTransferLength()
269  // It depends on MaxTransferLenth fields.
270  status = DeviceInitAllocateBuffers(deviceExtension);
271  }
272 
273  // 2. The following functions depend on the allocated buffers.
274 
275  // perf re-enable after failing. Q: Is this one used by cdrom.sys?
276  if (NT_SUCCESS(status))
277  {
278  // allow perf to be re-enabled after a given number of failed IOs
279  // require this number to be at least CLASS_PERF_RESTORE_MINIMUM
281 
282  DeviceGetParameter(deviceExtension,
285  &t);
287  {
288  deviceExtension->PrivateFdoData->Perf.ReEnableThreshhold = t;
289  }
290  }
291 
292  // 3. Retrieve information about special devices and hack flags.
293  if (NT_SUCCESS(status))
294  {
295  DeviceRetrieveHackFlagsFromRegistry(deviceExtension);
296  // scan for bad items.
297  DeviceScanForSpecial(deviceExtension, CdRomBadItems, DeviceHackFlagsScan);
298  // Check to see if it's a special device that needs special error process.
299  DeviceScanSpecialDevices(deviceExtension); // may send command to device
300  }
301 
302  // 4. Initialize the hotplug information only after the ScanForSpecial routines,
303  // as it relies upon the hack flags - deviceExtension->PrivateFdoData->HackFlags.
304  if (NT_SUCCESS(status))
305  {
306  status = DeviceInitializeHotplugInfo(deviceExtension);
307  }
308 
309  if (NT_SUCCESS(status))
310  {
311  // cache the device's inquiry data
312  status = DeviceCacheDeviceInquiryData(deviceExtension);
313  if (!NT_SUCCESS(status))
314  {
315  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT,
316  "Failed to cache the device's inquiry data, failng %!STATUS!\n",
317  status
318  ));
319  }
320  }
321 
322  // 5. Initialize MMC context, media change notification stuff and read media capacity
323  if (NT_SUCCESS(status))
324  {
325  status = DeviceInitializeMediaChangeDetection(deviceExtension);
326  }
327  if (NT_SUCCESS(status))
328  {
329  status = DeviceInitMmcContext(deviceExtension);
330  }
331  if (NT_SUCCESS(status))
332  {
333  status = DeviceInitializeZPODD(deviceExtension);
334  }
335  if (NT_SUCCESS(status))
336  {
337  // Do READ CAPACITY. This SCSI command returns the last sector address
338  // on the device and the bytes per sector. These are used to calculate
339  // the drive capacity in bytes.
340  status = MediaReadCapacity(Device);
341 
342  // If READ CAPACITY succeeded, we can safely conclude that there is a media present
343  if (NT_SUCCESS(status))
344  {
345  DeviceSetMediaChangeStateEx(deviceExtension,
346  MediaPresent,
347  NULL);
348  }
349 
350  // READ CAPACITY is not critical for init, ignore all errors occuring during its execution
352  }
353 
354  // 6. Perform DVD-specific initialization
355  if (NT_SUCCESS(status))
356  {
357  status = DeviceInitializeDvd(Device);
358  }
359 
360  // 7. Miscellaneous initialization actions
361  if (NT_SUCCESS(status))
362  {
363  if (deviceExtension->PrivateFdoData != NULL)
364  {
365  deviceExtension->PrivateFdoData->Perf.OriginalSrbFlags = deviceExtension->SrbFlags;
366  }
367 
368  if (deviceExtension->DeviceAdditionalData.Mmc.IsWriter)
369  {
370  // OPC can really take this long per IMAPIv1 timeout....
371  deviceExtension->TimeOutValue = max(deviceExtension->TimeOutValue, SCSI_CDROM_OPC_TIMEOUT);
372  }
373  }
374 
375  // 8. Enable the main timer, create ARC name as needed
376  if (NT_SUCCESS(status))
377  {
378  // Device successfully added and initialized, increase CdRomCount.
380 
381  deviceExtension->IsInitialized = TRUE;
382 
383  DeviceEnableMainTimer(deviceExtension);
384 
385  }
386 
387 #if (NTDDI_VERSION >= NTDDI_WIN8)
388  // 9. Set volume interface properties
389  if (NT_SUCCESS(status))
390  {
391  BOOLEAN isCritical = FALSE;
392  BOOLEAN isPortable = FALSE;
393  BOOLEAN isRemovable = TEST_FLAG(deviceExtension->DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA);
394  DEVPROP_BOOLEAN propCritical = DEVPROP_FALSE;
395  DEVPROP_BOOLEAN propPortable = DEVPROP_FALSE;
396  DEVPROP_BOOLEAN propRemovable = DEVPROP_FALSE;
397 
398  status = DeviceIsPortable(deviceExtension, &isPortable);
399 
400  if (NT_SUCCESS(status))
401  {
402  if (isPortable) {
403  SET_FLAG(deviceExtension->DeviceObject->Characteristics, FILE_PORTABLE_DEVICE);
404  }
405 
406  propPortable = isPortable ? DEVPROP_TRUE : DEVPROP_FALSE;
407 
408  status = IoSetDeviceInterfacePropertyData(&deviceExtension->MountedDeviceInterfaceName,
409  &DEVPKEY_Storage_Portable,
410  0,
411  0,
413  sizeof(DEVPROP_BOOLEAN),
414  &propPortable);
415  }
416 
417  if (NT_SUCCESS(status))
418  {
419  propRemovable = isRemovable ? DEVPROP_TRUE : DEVPROP_FALSE;
420 
421  status = IoSetDeviceInterfacePropertyData(&deviceExtension->MountedDeviceInterfaceName,
422  &DEVPKEY_Storage_Removable_Media,
423  0,
424  0,
426  sizeof(DEVPROP_BOOLEAN),
427  &propRemovable);
428  }
429 
430  if (NT_SUCCESS(status))
431  {
432  isCritical = TEST_FLAG(deviceExtension->DeviceObject->Flags,
436 
437  propCritical = isCritical ? DEVPROP_TRUE : DEVPROP_FALSE;
438 
439  status = IoSetDeviceInterfacePropertyData(&deviceExtension->MountedDeviceInterfaceName,
440  &DEVPKEY_Storage_System_Critical,
441  0,
442  0,
444  sizeof(DEVPROP_BOOLEAN),
445  &propCritical);
446  }
447 
448  }
449 #endif
450 
451  return status;
452 }
453 
454 
456 NTSTATUS
457 DeviceInitReleaseQueueContext(
458  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
459  )
460 /*++
461 
462 Routine Description:
463 
464  Part of device initialize routine. Initialize ReleaseQueue related stuff.
465 
466 Arguments:
467 
468  DeviceExtension - device extension of WDFDEVICE.
469 
470 Return Value:
471 
472  NTSTATUS
473 
474 --*/
475 {
477  WDF_OBJECT_ATTRIBUTES attributes;
478 
479  PAGED_CODE();
480 
483  attributes.ParentObject = DeviceExtension->Device;
484 
485  status = WdfRequestCreate(&attributes,
486  DeviceExtension->IoTarget,
487  &(DeviceExtension->ReleaseQueueRequest));
488 
489  if (!NT_SUCCESS(status))
490  {
491  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "Cannot create the release queue request\n"));
492 
493  return status;
494  }
495 
496  // Initialize ReleaseQueueInputMemory, a wrapper around ReleaseQueueSrb
497  WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
498  attributes.ParentObject = DeviceExtension->ReleaseQueueRequest;
499 
500  status = WdfMemoryCreatePreallocated(&attributes,
501  &DeviceExtension->ReleaseQueueSrb,
502  sizeof(SCSI_REQUEST_BLOCK),
503  &DeviceExtension->ReleaseQueueInputMemory);
504  if (!NT_SUCCESS(status))
505  {
506  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "Failed to allocate ReleaseQueueSrb.\n"));
507 
508  return status;
509  }
510 
511  // Preformat the release queue request here to ensure that this call will never
512  // fail during an actual release of the queue.
513  if (NT_SUCCESS(status))
514  {
515  status = WdfIoTargetFormatRequestForInternalIoctlOthers(DeviceExtension->IoTarget,
516  DeviceExtension->ReleaseQueueRequest,
518  DeviceExtension->ReleaseQueueInputMemory,
519  NULL,
520  NULL,
521  NULL,
522  NULL,
523  NULL);
524  }
525 
526  // Set a CompletionRoutine callback function for ReleaseQueueRequest.
527  if (NT_SUCCESS(status))
528  {
529  WdfRequestSetCompletionRoutine(DeviceExtension->ReleaseQueueRequest,
531  DeviceExtension->Device);
532  }
533 
534  // Create a spinlock for ReleaseQueueRequest
535  WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
536  attributes.ParentObject = DeviceExtension->Device;
537 
538  status = WdfSpinLockCreate(&attributes,
539  &(DeviceExtension->ReleaseQueueSpinLock));
540 
541  if (!NT_SUCCESS(status))
542  {
543  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP,
544  "DeviceInitReleaseQueueContext: Cannot create the release queue spinlock\n"));
545 
546  return status;
547  }
548 
549  // Initialize miscellaneous ReleaseQueue related fields
550  DeviceExtension->ReleaseQueueNeeded = FALSE;
551  DeviceExtension->ReleaseQueueInProgress = FALSE;
552  DeviceExtension->ReleaseQueueSrb.Length = sizeof(SCSI_REQUEST_BLOCK);
553 
554  return status;
555 }
556 
558 NTSTATUS
559 DeviceInitPowerContext(
560  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
561  )
562 /*++
563 
564 Routine Description:
565 
566  Part of device initialize routine. Initialize PowerContext related stuff.
567 
568 Arguments:
569 
570  DeviceExtension - device extension of WDFDEVICE.
571 
572 Return Value:
573 
574  NTSTATUS
575 
576 --*/
577 {
579  WDF_OBJECT_ATTRIBUTES attributes;
580 
581  PAGED_CODE();
582 
583  // create request object for Power operations
584 
587  attributes.ParentObject = DeviceExtension->Device;
588 
589  status = WdfRequestCreate(&attributes,
590  DeviceExtension->IoTarget,
591  &(DeviceExtension->PowerContext.PowerRequest) );
592 
593  if (!NT_SUCCESS(status))
594  {
595  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "Cannot create the power request object.\n"));
596 
597  return status;
598  }
599 
600  // Preformat the power request. With this being done, we never need to worry about
601  // WdfIoTargetFormatRequestForInternalIoctlOthers ever failing later.
602  status = WdfIoTargetFormatRequestForInternalIoctlOthers(DeviceExtension->IoTarget,
603  DeviceExtension->PowerContext.PowerRequest,
605  NULL, NULL,
606  NULL, NULL,
607  NULL, NULL);
608  return status;
609 }
610 
612 NTSTATUS
613 DeviceCreateWellKnownName(
614  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
615  )
616 /*++
617 
618 Routine Description:
619 
620  This routine creates a symbolic link to the cdrom device object
621  under \dosdevices. The number of the cdrom device does not neccessarily
622  match between \dosdevices and \device, but usually will be the same.
623 
624  Saves the buffer
625 
626 Arguments:
627 
628  DeviceObject -
629 
630 Return Value:
631 
632  NTSTATUS
633 
634 --*/
635 {
637  UNICODE_STRING unicodeLinkName = {0};
638  WCHAR wideLinkName[64] = {0};
639  PWCHAR savedName;
640 
641  LONG cdromNumber = DeviceExtension->DeviceNumber;
642 
643  PAGED_CODE();
644 
645  // if already linked, assert then return
646  if (DeviceExtension->DeviceAdditionalData.WellKnownName.Buffer != NULL)
647  {
648 
649  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT,
650  "DeviceCreateWellKnownName: link already exists %p\n",
651  DeviceExtension->DeviceAdditionalData.WellKnownName.Buffer));
652 
653  NT_ASSERT(FALSE);
654 
655  return STATUS_UNSUCCESSFUL;
656  }
657 
658  // find an unused CdRomNN to link to.
659  // It's doing this way because the same might be used for other device in another driver.
660  do
661  {
663  RTL_NUMBER_OF(wideLinkName),
664  L"\\DosDevices\\CdRom%d",
665  cdromNumber);
666  if (!NT_SUCCESS(status))
667  {
668  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT,
669  "DeviceCreateWellKnownName: Format symbolic link failed with error: 0x%X\n", status));
670  return status;
671  }
672 
673  RtlInitUnicodeString(&unicodeLinkName, wideLinkName);
674 
675  status = WdfDeviceCreateSymbolicLink(DeviceExtension->Device,
676  &unicodeLinkName);
677 
678  cdromNumber++;
679 
680  } while((status == STATUS_OBJECT_NAME_COLLISION) ||
682 
683  if (!NT_SUCCESS(status))
684  {
685  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT,
686  "DeviceCreateWellKnownName: Error %lx linking %wZ to "
687  "device %wZ\n",
688  status,
689  &unicodeLinkName,
690  &(DeviceExtension->DeviceName)));
691  return status;
692  }
693 
694  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
695  "DeviceCreateWellKnownName: successfully linked %wZ "
696  "to device %wZ\n",
697  &unicodeLinkName,
698  &(DeviceExtension->DeviceName)));
699 
700  // Save away the symbolic link name in the driver data block. We need
701  // it so we can delete the link when the device is removed.
702  savedName = ExAllocatePoolWithTag(PagedPool,
703  unicodeLinkName.MaximumLength,
705 
706  if (savedName == NULL)
707  {
708  // Test Note: test path should excise here to see if the symbolic is deleted by framework.
709  // IoDeleteSymbolicLink(&unicodeLinkName);
710  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT,
711  "DeviceCreateWellKnownName: unable to allocate memory.\n"));
712 
714  }
715 
716  RtlZeroMemory(savedName, unicodeLinkName.MaximumLength);
717  RtlCopyMemory(savedName, unicodeLinkName.Buffer, unicodeLinkName.MaximumLength);
718 
719  RtlInitUnicodeString(&(DeviceExtension->DeviceAdditionalData.WellKnownName), savedName);
720 
721  // the name was saved and the link created
722 
723  return STATUS_SUCCESS;
724 }
725 
727 NTSTATUS
728 DeviceRetrieveScsiAddress(
729  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
730  _In_ PSCSI_ADDRESS ScsiAddress
731  )
732 /*++
733 
734 Routine Description:
735 
736  retrieve SCSI address information and put into device extension
737 
738 Arguments:
739 
740  DeviceExtension - device context.
741  ScsiAddress - the buffer to put the scsi address info.
742 
743 Return Value:
744 
745  NTSTATUS
746 
747 --*/
748 {
750  WDF_MEMORY_DESCRIPTOR outputDescriptor;
751 
752  PAGED_CODE();
753 
754  if ((DeviceExtension == NULL) ||
755  (ScsiAddress == NULL))
756  {
758  }
759 
760  //Get IOTARGET for sending request to port driver.
761  WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&outputDescriptor,
762  (PVOID)ScsiAddress,
763  sizeof(SCSI_ADDRESS));
764 
765  status = WdfIoTargetSendIoctlSynchronously(DeviceExtension->IoTarget,
766  NULL,
768  NULL,
769  &outputDescriptor,
770  NULL,
771  NULL);
772 
773  if (!NT_SUCCESS(status))
774  {
775  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT,
776  "DeviceRetrieveScsiAddress: Get Address failed %lx\n",
777  status));
778  }
779  else
780  {
781  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT,
782  "GetAddress: Port %x, Path %x, Target %x, Lun %x\n",
783  ScsiAddress->PortNumber,
784  ScsiAddress->PathId,
785  ScsiAddress->TargetId,
786  ScsiAddress->Lun));
787  }
788 
789  return status;
790 }
791 
793 NTSTATUS
794 DeviceInitAllocateBuffers(
795  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
796  )
797 /*++
798 
799 Routine Description:
800 
801  Part of device initialize routine.
802  Allocate all buffers in Device Extension.
803 
804 Arguments:
805 
806  DeviceExtension - device extension of WDFDEVICE.
807 
808 Return Value:
809 
810  NTSTATUS
811 
812 --*/
813 {
815  PVOID senseData = NULL;
816 
817  PAGED_CODE();
818 
819  // allocate a private extension for class data
820  if (DeviceExtension->PrivateFdoData == NULL)
821  {
822  DeviceExtension->PrivateFdoData = ExAllocatePoolWithTag(NonPagedPoolNx,
823  sizeof(CDROM_PRIVATE_FDO_DATA),
825  }
826 
827  if (DeviceExtension->PrivateFdoData == NULL)
828  {
830  }
831  else
832  {
833  // initialize the struct's various fields.
834  RtlZeroMemory(DeviceExtension->PrivateFdoData, sizeof(CDROM_PRIVATE_FDO_DATA));
835  }
836 
837  // Allocate request sense buffer.
838  senseData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
841 
842  if (senseData == NULL)
843  {
844  // The buffer cannot be allocated.
846  }
847  else
848  {
849  // Set the sense data pointer in the device extension.
850  DeviceExtension->SenseData = senseData;
851  }
852 
853  // Allocate scratch buffer -- Must occur after determining
854  // max transfer size, but before other CD specific detection
855  // (which relies upon this buffer).
856  if (!ScratchBuffer_Allocate(DeviceExtension))
857  {
859  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT,
860  "Failed to allocate scratch buffer, failing %!STATUS!\n",
861  status
862  ));
863  }
864 
865  return status;
866 }
867 
869 NTSTATUS
870 DeviceRetrieveDescriptorsAndTransferLength(
871  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
872  )
873 /*++
874 
875 Routine Description:
876 
877  Part of device initialize routine.
878  Retrieve Device Descriptor and Adaptor Descriptor.
879 
880 Arguments:
881 
882  DeviceExtension - device extension of WDFDEVICE.
883 
884 Return Value:
885 
886  NTSTATUS
887 
888 --*/
889 {
891  STORAGE_PROPERTY_ID propertyId;
892 
893  PAGED_CODE();
894 
895  if (NT_SUCCESS(status))
896  {
897  // Call port driver to get adapter capabilities.
898  propertyId = StorageAdapterProperty;
899 
900  status = DeviceRetrieveDescriptor(DeviceExtension->Device,
901  &propertyId,
902  (PSTORAGE_DESCRIPTOR_HEADER*)&DeviceExtension->AdapterDescriptor);
903  }
904  if (NT_SUCCESS(status))
905  {
906  // Call port driver to get device descriptor.
907  propertyId = StorageDeviceProperty;
908 
909  status = DeviceRetrieveDescriptor(DeviceExtension->Device,
910  &propertyId,
911  (PSTORAGE_DESCRIPTOR_HEADER*)&DeviceExtension->DeviceDescriptor);
912  }
913  if (NT_SUCCESS(status))
914  {
915  // Call port driver to get device power property.
916  // Not all port drivers support this property, and it's not fatal if this query fails.
917  propertyId = StorageDevicePowerProperty;
918 
919  (void) DeviceRetrieveDescriptor(DeviceExtension->Device,
920  &propertyId,
921  (PSTORAGE_DESCRIPTOR_HEADER*)&DeviceExtension->PowerDescriptor);
922  }
923 
924  if (NT_SUCCESS(status))
925  {
926  // Determine the maximum page-aligned and non-page-aligned transfer
927  // lengths here, so we needn't do this in common READ/WRITE code paths
928 
929  // start with the number of pages the adapter can support
930  ULONG maxAlignedTransfer = DeviceExtension->AdapterDescriptor->MaximumPhysicalPages;
931  ULONG maxUnalignedTransfer = DeviceExtension->AdapterDescriptor->MaximumPhysicalPages;
932 
933 
934  // Unaligned buffers could cross a page boundary.
935  if (maxUnalignedTransfer > 1)
936  {
937  maxUnalignedTransfer--;
938  }
939 
940  // if we'd overflow multiplying by page size, just max out the
941  // transfer length allowed by the number of pages limit.
942  if (maxAlignedTransfer >= (((ULONG)-1) / PAGE_SIZE))
943  {
944  maxAlignedTransfer = (ULONG)-1;
945  }
946  else
947  {
948  maxAlignedTransfer *= PAGE_SIZE;
949  }
950 
951  if (maxUnalignedTransfer >= (((ULONG)-1) / PAGE_SIZE))
952  {
953  maxUnalignedTransfer = (ULONG)-1;
954  }
955  else
956  {
957  maxUnalignedTransfer *= PAGE_SIZE;
958  }
959 
960  // finally, take the smaller of the above and the adapter's
961  // reported maximum number of bytes per transfer.
962  maxAlignedTransfer = min(maxAlignedTransfer, DeviceExtension->AdapterDescriptor->MaximumTransferLength);
963  maxUnalignedTransfer = min(maxUnalignedTransfer, DeviceExtension->AdapterDescriptor->MaximumTransferLength);
964 
965  // Make sure the values are reasonable and not zero.
966  maxAlignedTransfer = max(maxAlignedTransfer, PAGE_SIZE);
967  maxUnalignedTransfer = max(maxUnalignedTransfer, PAGE_SIZE);
968 
969  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
970  "Device %p Max aligned/unaligned transfer size is %x/%x\n",
971  DeviceExtension->Device,
972  maxAlignedTransfer,
973  maxUnalignedTransfer
974  ));
975  DeviceExtension->DeviceAdditionalData.MaxPageAlignedTransferBytes = maxAlignedTransfer;
976  DeviceExtension->DeviceAdditionalData.MaxUnalignedTransferBytes = maxUnalignedTransfer;
977  }
978  else
979  {
980  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DeviceRetrieveDescriptorsAndTransferLength failed %lx\n", status));
981  }
982 
983  return status;
984 }
985 
986 
988 NTSTATUS
989 DeviceRetrieveDescriptor(
990  _In_ WDFDEVICE Device,
993  )
994 /*++
995 
996 Routine Description:
997 
998  This routine will perform a query for the specified property id and will
999  allocate a non-paged buffer to store the data in. It is the responsibility
1000  of the caller to ensure that this buffer is freed.
1001 
1002  This routine must be run at IRQL_PASSIVE_LEVEL
1003 
1004 Arguments:
1005 
1006  Device - the device object
1007  PropertyId - type of property to retrieve
1008  Descriptor - buffer allocated in this function to hold the descriptor data
1009 
1010 Return Value:
1011 
1012  status
1013 
1014 --*/
1015 {
1016  NTSTATUS status;
1017  WDF_MEMORY_DESCRIPTOR memoryDescriptor;
1018 
1020  ULONG bufferLength = 0;
1021 
1023  PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device);
1024 
1025  PAGED_CODE();
1026 
1027  // Set the passed-in descriptor pointer to NULL as default
1028  *Descriptor = NULL;
1029 
1030  // On the first pass we just want to get the first few
1031  // bytes of the descriptor so we can read it's size
1032  query.PropertyId = *PropertyId;
1033  query.QueryType = PropertyStandardQuery;
1034 
1035  descriptor = (PVOID)&query;
1036 
1037  NT_ASSERT(sizeof(STORAGE_PROPERTY_QUERY) >= (sizeof(ULONG)*2));
1038 
1039  WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memoryDescriptor,
1040  (PVOID)&query,
1041  sizeof(STORAGE_PROPERTY_QUERY));
1042 
1043  status = WdfIoTargetSendIoctlSynchronously(deviceExtension->IoTarget,
1044  NULL,
1046  &memoryDescriptor,
1047  &memoryDescriptor,
1048  NULL,
1049  NULL);
1050 
1051  if(!NT_SUCCESS(status))
1052  {
1053  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT, "DeviceRetrieveDescriptor: error %lx trying to "
1054  "query properties #1\n", status));
1055  return status;
1056  }
1057 
1058  if (descriptor->Size == 0)
1059  {
1060  // This DebugPrint is to help third-party driver writers
1061  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT, "DeviceRetrieveDescriptor: size returned was zero?! (status "
1062  "%x\n", status));
1063  return STATUS_UNSUCCESSFUL;
1064  }
1065 
1066  // This time we know how much data there is so we can
1067  // allocate a buffer of the correct size
1068  bufferLength = descriptor->Size;
1071 
1073 
1074  if(descriptor == NULL)
1075  {
1076  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT, "DeviceRetrieveDescriptor: unable to memory for descriptor "
1077  "(%d bytes)\n", bufferLength));
1079  }
1080 
1081  // setup the query again, as it was overwritten above
1083  query.PropertyId = *PropertyId;
1084  query.QueryType = PropertyStandardQuery;
1085 
1086  // copy the input to the new outputbuffer
1088  &query,
1089  sizeof(STORAGE_PROPERTY_QUERY));
1090 
1091  WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memoryDescriptor,
1092  (PVOID)descriptor,
1093  bufferLength);
1094 
1095  status = WdfIoTargetSendIoctlSynchronously(deviceExtension->IoTarget,
1096  NULL,
1098  &memoryDescriptor,
1099  &memoryDescriptor,
1100  NULL,
1101  NULL);
1102 
1103  if(!NT_SUCCESS(status))
1104  {
1105  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT, "DeviceRetrieveDescriptor: error %lx trying to "
1106  "query properties #1\n", status));
1108 
1109  return status;
1110  }
1111 
1112  // return the memory we've allocated to the caller
1114 
1115  return status;
1116 } // end DeviceRetrieveDescriptor()
1117 
1119 VOID
1120 DeviceRetrieveHackFlagsFromRegistry(
1121  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
1122  )
1123 /*++
1124 
1125 Routine Description:
1126 
1127  try to retrieve hack flages from registry and put the information in
1128  device extension.
1129 
1130 Arguments:
1131 
1132  DeviceExtension - the device context
1133 
1134 Return Value:
1135 
1136  none
1137 
1138 --*/
1139 {
1141  WDFKEY hardwareKey = NULL;
1142  WDFKEY subKey = NULL;
1143  ULONG deviceHacks = 0;
1144 
1147 
1148  PAGED_CODE();
1149 
1150  status = WdfDeviceOpenRegistryKey(DeviceExtension->Device,
1152  KEY_READ,
1154  &hardwareKey);
1155  if (NT_SUCCESS(status))
1156  {
1157  status = WdfRegistryOpenKey(hardwareKey,
1158  &subKeyName,
1159  KEY_READ,
1161  &subKey);
1162 
1163  if (NT_SUCCESS(status))
1164  {
1165  status = WdfRegistryQueryULong(subKey,
1166  &valueName,
1167  &deviceHacks);
1168  if (NT_SUCCESS(status))
1169  {
1170  // remove unknown values and save...
1171  CLEAR_FLAG(deviceHacks, FDO_HACK_INVALID_FLAGS);
1172  SET_FLAG(DeviceExtension->PrivateFdoData->HackFlags, deviceHacks);
1173  }
1174 
1175  WdfRegistryClose(subKey);
1176  }
1177 
1178  WdfRegistryClose(hardwareKey);
1179  }
1180 
1181 
1182  //
1183  // we should modify the system hive to include another key for us to grab
1184  // settings from. in this case: Classpnp\HackFlags
1185  //
1186  // the use of a DWORD value for the HackFlags allows 32 hacks w/o
1187  // significant use of the registry, and also reduces OEM exposure.
1188  //
1189  // definition of bit flags:
1190  // 0x00000001 -- Device succeeds PREVENT_MEDIUM_REMOVAL, but
1191  // cannot actually prevent removal.
1192  // 0x00000002 -- Device hard-hangs or times out for GESN requests.
1193  // 0x00000008 -- Device does not support RESERVE(6) and RELEASE(6).
1194  // 0x00000010 -- Device may incorrecly report operational changes in GESN.
1195  // 0x00000020 -- Device does not support streaming READ(12) / WRITE(12).
1196  // 0x00000040 -- Device does not support asynchronous notification.
1197  // 0xffffff80 -- Currently reserved, may be used later.
1198  //
1199 
1200  return;
1201 }
1202 
1204 VOID DeviceScanForSpecial(
1205  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
1208 /*++
1209 
1210 Routine Description:
1211 
1212  scan the list of devices that should be hacked or not supported.
1213 
1214 Arguments:
1215 
1216  DeviceExtension - the device context
1217  DeviceList - the device list
1218  Function - function used to scan from the list.
1219 
1220 Return Value:
1221 
1222  none
1223 
1224 --*/
1225 {
1226  PSTORAGE_DEVICE_DESCRIPTOR deviceDescriptor;
1227  PUCHAR vendorId;
1228  PUCHAR productId;
1229  PUCHAR productRevision;
1230  UCHAR nullString[] = "";
1231 
1232  PAGED_CODE();
1235 
1236  if (DeviceList == NULL)
1237  {
1238  return;
1239  }
1240  if (Function == NULL)
1241  {
1242  return;
1243  }
1244 
1245  deviceDescriptor = DeviceExtension->DeviceDescriptor;
1246 
1247  // SCSI sets offsets to -1, ATAPI sets to 0. check for both.
1248  if (deviceDescriptor->VendorIdOffset != 0 &&
1249  deviceDescriptor->VendorIdOffset != -1)
1250  {
1251  vendorId = ((PUCHAR)deviceDescriptor);
1252  vendorId += deviceDescriptor->VendorIdOffset;
1253  }
1254  else
1255  {
1256  vendorId = nullString;
1257  }
1258 
1259  if (deviceDescriptor->ProductIdOffset != 0 &&
1260  deviceDescriptor->ProductIdOffset != -1)
1261  {
1262  productId = ((PUCHAR)deviceDescriptor);
1263  productId += deviceDescriptor->ProductIdOffset;
1264  }
1265  else
1266  {
1267  productId = nullString;
1268  }
1269 
1270  if (deviceDescriptor->ProductRevisionOffset != 0 &&
1271  deviceDescriptor->ProductRevisionOffset != -1)
1272  {
1273  productRevision = ((PUCHAR)deviceDescriptor);
1274  productRevision += deviceDescriptor->ProductRevisionOffset;
1275  }
1276  else
1277  {
1278  productRevision = nullString;
1279  }
1280 
1281  // loop while the device list is valid (not null-filled)
1282  for (;(DeviceList->VendorId != NULL ||
1283  DeviceList->ProductId != NULL ||
1284  DeviceList->ProductRevision != NULL); DeviceList++)
1285  {
1286  if (StringsAreMatched(DeviceList->VendorId, (LPSTR)vendorId) &&
1287  StringsAreMatched(DeviceList->ProductId, (LPSTR)productId) &&
1288  StringsAreMatched(DeviceList->ProductRevision, (LPSTR)productRevision)
1289  )
1290  {
1291 
1292  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, "DeviceScanForSpecial: Found matching "
1293  "controller Ven: %s Prod: %s Rev: %s\n",
1294  (LPCSTR)vendorId, (LPCSTR)productId, (LPCSTR)productRevision));
1295 
1296  // pass the context to the call back routine and exit
1297  (Function)(DeviceExtension, DeviceList->Data);
1298 
1299  // for CHK builds, try to prevent wierd stacks by having a debug
1300  // print here. it's a hack, but i know of no other way to prevent
1301  // the stack from being wrong.
1302  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, "DeviceScanForSpecial: "
1303  "completed callback\n"));
1304  return;
1305 
1306  } // else the strings did not match
1307 
1308  } // none of the devices matched.
1309 
1310  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, "DeviceScanForSpecial: no match found for %p\n",
1311  DeviceExtension->DeviceObject));
1312  return;
1313 
1314 } // end DeviceScanForSpecial()
1315 
1317 VOID
1318 DeviceHackFlagsScan(
1319  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
1321  )
1322 {
1323  PAGED_CODE();
1324 
1325  // remove invalid flags and save
1327  SET_FLAG(DeviceExtension->PrivateFdoData->HackFlags, Data);
1328 
1329  return;
1330 }
1331 
1332 
1334 NTSTATUS
1335 DeviceInitializeHotplugInfo(
1336  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
1337  )
1338 /*++
1339 
1340 Routine Description:
1341 
1342  Retrieve information into struc STORAGE_HOTPLUG_INFO in DeviceExtension
1343  initialize the hotplug information only after the ScanForSpecial routines,
1344  as it relies upon the hack flags - DeviceExtension->PrivateFdoData->HackFlags.
1345 
1346 Arguments:
1347 
1348  DeviceExtension - the device context
1349 
1350 Return Value:
1351 
1352  NTSTATUS
1353 
1354 --*/
1355 {
1357  PCDROM_PRIVATE_FDO_DATA fdoData = DeviceExtension->PrivateFdoData;
1358  DEVICE_REMOVAL_POLICY deviceRemovalPolicy = 0;
1359  ULONG resultLength = 0;
1360  ULONG writeCacheOverride;
1361 
1362  PAGED_CODE();
1363 
1364  // start with some default settings
1365  RtlZeroMemory(&(fdoData->HotplugInfo), sizeof(STORAGE_HOTPLUG_INFO));
1366 
1367  // set the size (aka version)
1368  fdoData->HotplugInfo.Size = sizeof(STORAGE_HOTPLUG_INFO);
1369 
1370  // set if the device has removable media
1371  if (DeviceExtension->DeviceDescriptor->RemovableMedia)
1372  {
1373  fdoData->HotplugInfo.MediaRemovable = TRUE;
1374  }
1375  else
1376  {
1377  fdoData->HotplugInfo.MediaRemovable = FALSE;
1378  }
1379 
1380  //
1381  // this refers to devices which, for reasons not yet understood,
1382  // do not fail PREVENT_MEDIA_REMOVAL requests even though they
1383  // have no way to lock the media into the drive. this allows
1384  // the filesystems to turn off delayed-write caching for these
1385  // devices as well.
1386  //
1387 
1388  if (TEST_FLAG(DeviceExtension->PrivateFdoData->HackFlags, FDO_HACK_CANNOT_LOCK_MEDIA))
1389  {
1390  fdoData->HotplugInfo.MediaHotplug = TRUE;
1391  }
1392  else
1393  {
1394  fdoData->HotplugInfo.MediaHotplug = FALSE;
1395  }
1396 
1397  // Query the default removal policy from the kernel
1398  status = WdfDeviceQueryProperty(DeviceExtension->Device,
1400  sizeof(DEVICE_REMOVAL_POLICY),
1401  (PVOID)&deviceRemovalPolicy,
1402  &resultLength);
1403  if (NT_SUCCESS(status))
1404  {
1405  if (resultLength != sizeof(DEVICE_REMOVAL_POLICY))
1406  {
1408  }
1409  }
1410 
1411  if (NT_SUCCESS(status))
1412  {
1413  // Look into the registry to see if the user has chosen
1414  // to override the default setting for the removal policy.
1415  // User can override only if the default removal policy is
1416  // orderly or suprise removal.
1417 
1418  if ((deviceRemovalPolicy == RemovalPolicyExpectOrderlyRemoval) ||
1419  (deviceRemovalPolicy == RemovalPolicyExpectSurpriseRemoval))
1420  {
1421  DEVICE_REMOVAL_POLICY userRemovalPolicy = 0;
1422 
1423  DeviceGetParameter(DeviceExtension,
1426  (PULONG)&userRemovalPolicy);
1427 
1428  // Validate the override value and use it only if it is an
1429  // allowed value.
1430  if ((userRemovalPolicy == RemovalPolicyExpectOrderlyRemoval) ||
1431  (userRemovalPolicy == RemovalPolicyExpectSurpriseRemoval))
1432  {
1433  deviceRemovalPolicy = userRemovalPolicy;
1434  }
1435  }
1436 
1437  // use this info to set the DeviceHotplug setting
1438  // don't rely on DeviceCapabilities, since it can't properly
1439  // determine device relations, etc. let the kernel figure this
1440  // stuff out instead.
1441  if (deviceRemovalPolicy == RemovalPolicyExpectSurpriseRemoval)
1442  {
1443  fdoData->HotplugInfo.DeviceHotplug = TRUE;
1444  }
1445  else
1446  {
1447  fdoData->HotplugInfo.DeviceHotplug = FALSE;
1448  }
1449 
1450  // this refers to the *filesystem* caching, but has to be included
1451  // here since it's a per-device setting. this may change to be
1452  // stored by the system in the future.
1453  writeCacheOverride = FALSE;
1454  DeviceGetParameter(DeviceExtension,
1457  &writeCacheOverride);
1458 
1459  if (writeCacheOverride)
1460  {
1462  }
1463  else
1464  {
1466  }
1467  }
1468 
1469  if (!NT_SUCCESS(status))
1470  {
1471  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT, "Could not initialize hotplug information %lx\n", status));
1472  }
1473 
1474  return status;
1475 }
1476 
1477 
1479 NTSTATUS
1480 DeviceInitMmcContext(
1481  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
1482  )
1483 /*++
1484 
1485 Routine Description:
1486 
1487  This routine initializes and populates the internal data structures that are
1488  used to discover various MMC-defined capabilities of the device.
1489 
1490  This routine will not clean up allocate resources if it fails - that
1491  is left for device stop/removal routines
1492 
1493 Arguments:
1494 
1495  DeviceExtension - device extension
1496 
1497 Return Value:
1498 
1499  NTSTATUS
1500 
1501 --*/
1502 {
1504 
1505  PAGED_CODE();
1506 
1507  DeviceExtension->DeviceAdditionalData.Mmc.IsMmc = FALSE;
1508  DeviceExtension->DeviceAdditionalData.Mmc.IsAACS = FALSE;
1509  DeviceExtension->DeviceAdditionalData.Mmc.IsWriter = FALSE;
1510  DeviceExtension->DeviceAdditionalData.Mmc.WriteAllowed = FALSE;
1511  DeviceExtension->DeviceAdditionalData.Mmc.IsCssDvd = FALSE;
1512  DeviceExtension->DeviceAdditionalData.DriveDeviceType = FILE_DEVICE_CD_ROM;
1513 
1514  // Determine if the drive is MMC-Capable
1515  if (NT_SUCCESS(status))
1516  {
1517  status = DeviceGetMmcSupportInfo(DeviceExtension,
1518  &DeviceExtension->DeviceAdditionalData.Mmc.IsMmc);
1519 
1520  if (!NT_SUCCESS(status))
1521  {
1522  //Currently, only low resource error comes here.
1523  //That is a success case for unsupporting this command.
1524  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT,
1525  "DeviceInitMmcContext: Failed to get the support info for GET CONFIGURATION "
1526  "command, failng %!STATUS!\n", status
1527  ));
1528 
1529  DeviceExtension->DeviceAdditionalData.Mmc.IsMmc = FALSE;
1531  }
1532  }
1533 
1534  if (NT_SUCCESS(status) && DeviceExtension->DeviceAdditionalData.Mmc.IsMmc)
1535  {
1536  // the drive supports at least a subset of MMC commands
1537  // (and therefore supports READ_CD, etc...)
1538 
1539  // allocate a buffer for all the capabilities and such
1540  status = DeviceAllocateMmcResources(DeviceExtension->Device);
1541  }
1542 
1543  if (NT_SUCCESS(status) && DeviceExtension->DeviceAdditionalData.Mmc.IsMmc)
1544  {
1546  FEATURE_NUMBER validationSchema;
1547  ULONG blockingFactor;
1548 
1549  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
1550  "DeviceInitMmcContext: FDO %p GET CONFIGURATION buffer %p\n",
1551  DeviceExtension->Device,
1552  DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBuffer
1553  ));
1554 
1555  // Update several properties using the retrieved Configuration Data.
1556 
1557  // print all the feature pages (DBG only)
1558  DevicePrintAllFeaturePages(DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBuffer,
1559  DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBufferSize);
1560 
1561  // if AACS feature exists, enable AACS flag in the driver
1562  header = DeviceFindFeaturePage(DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBuffer,
1563  DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBufferSize,
1564  FeatureAACS);
1565  if (header)
1566  {
1567  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
1568  "DeviceInitMmcContext: Reporting AACS support for device due to "
1569  "GET CONFIGURATION showing support\n"
1570  ));
1571  DeviceExtension->DeviceAdditionalData.Mmc.IsAACS = TRUE;
1572  }
1573 
1574 #ifdef ENABLE_AACS_TESTING
1575  DeviceExtension->DeviceAdditionalData.Mmc.IsAACS = TRUE; // just force it true for testing
1576 #endif // ENABLE_AACS_TESTING
1577 
1578  // Check if it's a DVD device
1579  header = DeviceFindFeaturePage(DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBuffer,
1580  DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBufferSize,
1581  FeatureDvdRead);
1582  if (header != NULL)
1583  {
1584  DeviceExtension->DeviceAdditionalData.DriveDeviceType = FILE_DEVICE_DVD;
1585  }
1586 
1587  // check if drive is writer
1588  DeviceUpdateMmcWriteCapability(DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBuffer,
1589  DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBufferSize,
1590  FALSE, //Check if the drive has the ability to write.
1591  (PBOOLEAN)&(DeviceExtension->DeviceAdditionalData.Mmc.IsWriter),
1592  &validationSchema,
1593  &blockingFactor);
1594 
1595  // check if there is a CSS protected DVD or CPPM-protected DVDAudio media in drive.
1596  header = DeviceFindFeaturePage(DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBuffer,
1597  DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBufferSize,
1598  FeatureDvdCSS);
1599 
1600  DeviceExtension->DeviceAdditionalData.Mmc.IsCssDvd = (header != NULL) && (header->Current);
1601 
1602  // Flag the StartIo routine to update its state and hook in the error handler
1603  DeviceExtension->DeviceAdditionalData.Mmc.UpdateState = CdromMmcUpdateRequired;
1604  DeviceExtension->DeviceAdditionalData.ErrorHandler = DeviceErrorHandlerForMmc;
1605 
1606  SET_FLAG(DeviceExtension->DeviceFlags, DEV_SAFE_START_UNIT);
1607 
1608  // Read the CDROM mode sense page to get additional info for raw read requests.
1609  // only valid for MMC devices
1610  DeviceSetRawReadInfo(DeviceExtension);
1611  }
1612 
1613  // Set Read-Only device flag for non-MMC device.
1614  if (!(DeviceExtension->DeviceAdditionalData.Mmc.IsMmc))
1615  {
1616  ULONG deviceCharacteristics = WdfDeviceGetCharacteristics(DeviceExtension->Device);
1617 
1618  deviceCharacteristics |= FILE_READ_ONLY_DEVICE;
1619 
1620  WdfDeviceSetCharacteristics(DeviceExtension->Device, deviceCharacteristics);
1621 
1622  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
1623  "DeviceInitMmcContext: FDO %p Device is not an MMC compliant device, so setting "
1624  "to read-only (legacy) mode",
1625  DeviceExtension->Device
1626  ));
1627  }
1628 
1629  // Set DEV_SAFE_START_UNIT flag for newer devices.
1630  if (DeviceExtension->DeviceAdditionalData.DriveDeviceType == FILE_DEVICE_DVD)
1631  {
1632  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
1633  "DeviceInitMmcContext: DVD Devices require START UNIT\n"));
1634  SET_FLAG(DeviceExtension->DeviceFlags, DEV_SAFE_START_UNIT);
1635 
1636  }
1637  else if ((DeviceExtension->DeviceDescriptor->BusType != BusTypeScsi) &&
1638  (DeviceExtension->DeviceDescriptor->BusType != BusTypeAtapi) &&
1639  (DeviceExtension->DeviceDescriptor->BusType != BusTypeUnknown)
1640  )
1641  {
1642  // devices on the newer busses require START_UNIT
1643  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
1644  "DeviceInitMmcContext: Devices for newer buses require START UNIT\n"));
1645  SET_FLAG(DeviceExtension->DeviceFlags, DEV_SAFE_START_UNIT);
1646  }
1647 
1648  return status;
1649 }
1650 
1651 
1653 ULONG
1654 DeviceGetTimeOutValueFromRegistry()
1655 /*++
1656 
1657 Routine Description:
1658 
1659  get the device time out value from registry
1660 
1661 Arguments:
1662 
1663  None
1664 
1665 Return Value:
1666 
1667  ULONG - value of timeout
1668 
1669 --*/
1670 {
1671  NTSTATUS status;
1672  WDFKEY registryKey = NULL;
1673  ULONG timeOutValue = 0;
1674 
1675  DECLARE_CONST_UNICODE_STRING(registryValueName, L"TimeOutValue");
1676 
1677  PAGED_CODE();
1678 
1679  // open the service key.
1680  status = WdfDriverOpenParametersRegistryKey(WdfGetDriver(),
1681  KEY_READ,
1683  &registryKey);
1684 
1685  if (NT_SUCCESS(status))
1686  {
1687  status = WdfRegistryQueryULong(registryKey,
1688  &registryValueName,
1689  &timeOutValue);
1690 
1691  WdfRegistryClose(registryKey);
1692  }
1693 
1694  if (!NT_SUCCESS(status))
1695  {
1696  timeOutValue = 0;
1697  }
1698 
1699  return timeOutValue;
1700 
1701 } // end DeviceGetTimeOutValueFromRegistry()
1702 
1703 
1705 VOID
1706 DeviceScanSpecialDevices(
1707  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
1708  )
1709 /*++
1710 
1711 Routine Description:
1712 
1713  This function checks to see if an SCSI logical unit requires an special
1714  initialization or error processing.
1715 
1716 Arguments:
1717 
1718  Device - device object.
1719 
1720 Return Value:
1721 
1722  None.
1723 
1724 --*/
1725 {
1726 
1727  PAGED_CODE();
1728 
1729  // set our hack flags
1730  DeviceScanForSpecial(DeviceExtension, CdromHackItems, ScanForSpecialHandler);
1731 
1732  //
1733  // All CDRom's can ignore the queue lock failure for power operations
1734  // and do not require handling the SpinUp case (unknown result of sending
1735  // a cdrom a START_UNIT command -- may eject disks?)
1736  //
1737  // We send the stop command mostly to stop outstanding asynch operations
1738  // (like audio playback) from running when the system is powered off.
1739  // Because of this and the unlikely chance that a PLAY command will be
1740  // sent in the window between the STOP and the time the machine powers down
1741  // we don't require queue locks. This is important because without them
1742  // classpnp's power routines will send the START_STOP_UNIT command to the
1743  // device whether or not it supports locking (atapi does not support locking
1744  // and if we requested them we would end up not stopping audio on atapi
1745  // devices).
1746 // SET_FLAG(deviceExtension->ScanForSpecialFlags, CDROM_SPECIAL_DISABLE_SPIN_UP);
1747 // SET_FLAG(deviceExtension->ScanForSpecialFlags, CDROM_SPECIAL_NO_QUEUE_LOCK);
1748 
1749  if (TEST_FLAG(DeviceExtension->DeviceAdditionalData.HackFlags, CDROM_HACK_TOSHIBA_SD_W1101))
1750  {
1751  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
1752  "DeviceScanSpecialDevices: Found Toshiba SD-W1101 DVD-RAM "
1753  "-- This drive will *NOT* support DVD-ROM playback.\n"));
1754  }
1755  else if (TEST_FLAG(DeviceExtension->DeviceAdditionalData.HackFlags, CDROM_HACK_HITACHI_GD_2000))
1756  {
1757  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
1758  "DeviceScanSpecialDevices: Found Hitachi GD-2000\n"));
1759 
1760  // Setup an error handler to spin up the drive when it idles out
1761  // since it seems to like to fail to spin itself back up on its
1762  // own for a REPORT_KEY command. It may also lose the AGIDs that
1763  // it has given, which will result in DVD playback failures.
1764  // This routine will just do what it can...
1765  DeviceExtension->DeviceAdditionalData.ErrorHandler = DeviceErrorHandlerForHitachiGD2000;
1766 
1767  // this drive may require START_UNIT commands to spin
1768  // the drive up when it's spun itself down.
1769  SET_FLAG(DeviceExtension->DeviceFlags, DEV_SAFE_START_UNIT);
1770  }
1771  else if (TEST_FLAG(DeviceExtension->DeviceAdditionalData.HackFlags, CDROM_HACK_FUJITSU_FMCD_10x))
1772  {
1773  // When Read command is issued to FMCD-101 or FMCD-102 and there is a music
1774  // cd in it. It takes longer time than SCSI_CDROM_TIMEOUT before returning
1775  // error status.
1776  DeviceExtension->TimeOutValue = 20;
1777  }
1778  else if (TEST_FLAG(DeviceExtension->DeviceAdditionalData.HackFlags, CDROM_HACK_DEC_RRD))
1779  {
1780  NTSTATUS status;
1781  PMODE_PARM_READ_WRITE_DATA modeParameters;
1782  SCSI_REQUEST_BLOCK srb = {0};
1783  PCDB cdb;
1784 
1785  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
1786  "DeviceScanSpecialDevices: Found DEC RRD.\n"));
1787 
1788  DeviceExtension->DeviceAdditionalData.IsDecRrd = TRUE;
1789 
1790  // Setup an error handler to reinitialize the cd rom after it is reset?
1791  //
1792  //DeviceExtension->DevInfo->ClassError = DecRrdProcessError;
1793 
1794  // Found a DEC RRD cd-rom. These devices do not pass MS HCT
1795  // multi-media tests because the DEC firmware modifieds the block
1796  // from the PC-standard 2K to 512. Change the block transfer size
1797  // back to the PC-standard 2K by using a mode select command.
1798 
1799  modeParameters = ExAllocatePoolWithTag(NonPagedPoolNx,
1800  sizeof(MODE_PARM_READ_WRITE_DATA),
1802  if (modeParameters == NULL)
1803  {
1804  return;
1805  }
1806 
1807  RtlZeroMemory(modeParameters, sizeof(MODE_PARM_READ_WRITE_DATA));
1808  RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
1809 
1810  // Set the block length to 2K.
1812 
1813  // Set block length to 2K (0x0800) in Parameter Block.
1814  modeParameters->ParameterListBlock.BlockLength[0] = 0x00; //MSB
1815  modeParameters->ParameterListBlock.BlockLength[1] = 0x08;
1816  modeParameters->ParameterListBlock.BlockLength[2] = 0x00; //LSB
1817 
1818  // Build the mode select CDB.
1819  srb.CdbLength = 6;
1820  srb.TimeOutValue = DeviceExtension->TimeOutValue;
1821 
1822  cdb = (PCDB)srb.Cdb;
1823  cdb->MODE_SELECT.PFBit = 1;
1824  cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
1825  cdb->MODE_SELECT.ParameterListLength = HITACHI_MODE_DATA_SIZE;
1826 
1827  // Send the request to the device.
1828  status = DeviceSendSrbSynchronously(DeviceExtension->Device,
1829  &srb,
1830  modeParameters,
1831  sizeof(MODE_PARM_READ_WRITE_DATA),
1832  TRUE,
1833  NULL);
1834 
1835  if (!NT_SUCCESS(status))
1836  {
1837  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT,
1838  "DeviceScanSpecialDevices: Setting DEC RRD to 2K block"
1839  "size failed [%x]\n", status));
1840  }
1841 
1842  ExFreePool(modeParameters);
1843  }
1844 
1845  return;
1846 }
1847 
1849 VOID
1850 ScanForSpecialHandler(
1851  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
1853  )
1854 {
1855  PAGED_CODE();
1856 
1858 
1859  DeviceExtension->DeviceAdditionalData.HackFlags = HackFlags;
1860 
1861  return;
1862 }
1863 
1864 
1866 NTSTATUS
1867 DeviceCacheDeviceInquiryData(
1868  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
1869  )
1870 /*++
1871 
1872 Routine Description:
1873 
1874  get inquiry data from device and cache it into device extension
1875  The first INQUIRY command sent is with 0x24 bytes required data,
1876  as ATAport driver always sends this to enumerate devices and 0x24
1877  bytes is the minimum data device should return by spec.
1878 
1879 Arguments:
1880 
1881  DeviceExtension - device extension.
1882 
1883 Return Value:
1884 
1885  NTSTATUS.
1886 
1887 --*/
1888 {
1890  SCSI_REQUEST_BLOCK srb = {0};
1891  PCDB cdb = (PCDB)(&srb.Cdb);
1892  PINQUIRYDATA tmpInquiry = NULL;
1893 
1894  // by spec, device should return at least 36 bytes.
1895  ULONG requestedInquiryTransferBytes = MINIMUM_CDROM_INQUIRY_SIZE;
1896  BOOLEAN needResendCommand = TRUE;
1897  BOOLEAN portDriverHack = FALSE;
1898 
1899  // this ensures that the strings vendorID, productID, and firmwareRevision
1900  // are all available in the inquiry data. In addition, MMC spec requires
1901  // all type 5 devices to have minimum 36 bytes of inquiry.
1902  static const UCHAR minInquiryAdditionalLength =
1904  RTL_SIZEOF_THROUGH_FIELD(INQUIRYDATA, AdditionalLength);
1905 
1906  C_ASSERT( RTL_SIZEOF_THROUGH_FIELD(INQUIRYDATA, AdditionalLength) <= 8 );
1908 
1909  PAGED_CODE();
1910 
1911  // short-circuit here for if already cached for this device
1912  // required to avoid use of scratch buffer after initialization
1913  // of MCN code.
1914  if (DeviceExtension->DeviceAdditionalData.CachedInquiryData != NULL)
1915  {
1916  NT_ASSERT(DeviceExtension->DeviceAdditionalData.CachedInquiryDataByteCount != 0);
1917  return STATUS_SUCCESS;
1918  }
1919 
1920  // 1. retrieve the inquiry data length
1921 
1922  // 1.1 allocate inquiry data buffer
1923  tmpInquiry = ExAllocatePoolWithTag(NonPagedPoolNx,
1924  requestedInquiryTransferBytes,
1926  if (tmpInquiry == NULL)
1927  {
1929  }
1930 
1931  // 1.2 send INQUIRY command
1932  if (NT_SUCCESS(status))
1933  {
1934  srb.CdbLength = 6;
1935  cdb->AsByte[0] = SCSIOP_INQUIRY;
1936  cdb->AsByte[3] = (UCHAR)( requestedInquiryTransferBytes >> (8*1) );
1937  cdb->AsByte[4] = (UCHAR)( requestedInquiryTransferBytes >> (8*0) );
1938 
1939  status = DeviceSendSrbSynchronously(DeviceExtension->Device,
1940  &srb,
1941  tmpInquiry,
1942  requestedInquiryTransferBytes,
1943  FALSE,
1944  NULL);
1945  }
1946 
1947  // 1.3 get required data length
1948  if (NT_SUCCESS(status))
1949  {
1950  if ((requestedInquiryTransferBytes == srb.DataTransferLength) &&
1951  (requestedInquiryTransferBytes == (tmpInquiry->AdditionalLength +
1952  RTL_SIZEOF_THROUGH_FIELD(INQUIRYDATA, AdditionalLength))) )
1953  {
1954  // device has only 36 bytes of INQUIRY data. do not need to resend the command.
1955  needResendCommand = FALSE;
1956  }
1957  else
1958  {
1959  // workaround an ATAPI.SYS bug where additional length field is set to zero
1960  if (tmpInquiry->AdditionalLength == 0)
1961  {
1962  tmpInquiry->AdditionalLength = minInquiryAdditionalLength;
1963  portDriverHack = TRUE;
1964  }
1965 
1966  requestedInquiryTransferBytes =
1967  tmpInquiry->AdditionalLength +
1968  RTL_SIZEOF_THROUGH_FIELD(INQUIRYDATA, AdditionalLength);
1969 
1970  if (requestedInquiryTransferBytes >= MINIMUM_CDROM_INQUIRY_SIZE)
1971  {
1972  needResendCommand = TRUE;
1973  }
1974  else
1975  {
1976  needResendCommand = FALSE;
1977  //Length is small than minimum length, error out.
1979  }
1980  }
1981  }
1982 
1983  // 2. retrieve the inquiry data if still needed.
1984 
1985  // 2.1 Clean up.
1986  if (NT_SUCCESS(status) && needResendCommand)
1987  {
1988  FREE_POOL(tmpInquiry);
1989  RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
1990 
1991  tmpInquiry = ExAllocatePoolWithTag(NonPagedPoolNx,
1992  requestedInquiryTransferBytes,
1994  if (tmpInquiry == NULL)
1995  {
1997  }
1998  }
1999 
2000  // 2.2 resend INQUIRY command
2001  if (NT_SUCCESS(status) && needResendCommand)
2002  {
2003  srb.CdbLength = 6;
2004  cdb->AsByte[0] = SCSIOP_INQUIRY;
2005  cdb->AsByte[3] = (UCHAR)( requestedInquiryTransferBytes >> (8*1) );
2006  cdb->AsByte[4] = (UCHAR)( requestedInquiryTransferBytes >> (8*0) );
2007 
2008  status = DeviceSendSrbSynchronously( DeviceExtension->Device,
2009  &srb,
2010  tmpInquiry,
2011  requestedInquiryTransferBytes,
2012  FALSE,
2013  NULL);
2014 
2015  if (!NT_SUCCESS(status))
2016  {
2017  // Workaround for drive reports that it has more INQUIRY data than reality.
2018  if ((srb.SrbStatus == SRB_STATUS_DATA_OVERRUN) &&
2019  (srb.DataTransferLength < requestedInquiryTransferBytes) &&
2021  {
2022  //Port driver says buffer size mismatch (buffer underrun),
2023  //retry with the real buffer size it could return.
2024  requestedInquiryTransferBytes = srb.DataTransferLength;
2025 
2026  FREE_POOL(tmpInquiry);
2027  RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
2028 
2029  tmpInquiry = ExAllocatePoolWithTag(NonPagedPoolNx,
2030  requestedInquiryTransferBytes,
2032  if (tmpInquiry == NULL)
2033  {
2035  }
2036  else
2037  {
2038  srb.CdbLength = 6;
2039  cdb->AsByte[0] = SCSIOP_INQUIRY;
2040  cdb->AsByte[3] = (UCHAR)( requestedInquiryTransferBytes >> (8*1) );
2041  cdb->AsByte[4] = (UCHAR)( requestedInquiryTransferBytes >> (8*0) );
2042 
2043  status = DeviceSendSrbSynchronously(DeviceExtension->Device,
2044  &srb,
2045  tmpInquiry,
2046  requestedInquiryTransferBytes,
2047  FALSE,
2048  NULL);
2049  }
2050  }
2051  }
2052 
2053  //Check the transferred data length for safe.
2054  if (NT_SUCCESS(status))
2055  {
2056  requestedInquiryTransferBytes = srb.DataTransferLength;
2057 
2058  if (requestedInquiryTransferBytes < MINIMUM_CDROM_INQUIRY_SIZE)
2059  {
2060  // should never occur
2062  }
2063  }
2064 
2065  // ensure we got some non-zero data....
2066  // This is done so we don't accidentally work around the
2067  // ATAPI.SYS bug when no data was transferred.
2068  if (NT_SUCCESS(status) && portDriverHack)
2069  {
2070  PULONG tmp = (PULONG)tmpInquiry;
2072  C_ASSERT( RTL_SIZEOF_THROUGH_FIELD(INQUIRYDATA, ProductRevisionLevel) % sizeof(ULONG) == 0 );
2073 
2074  // wouldn't you know it -- there is no RtlIsMemoryZero() function; Make one up.
2075  for ( ; i != 0; i--)
2076  {
2077  if (*tmp != 0)
2078  {
2079  break; // out of this inner FOR loop -- guarantees 'i != 0'
2080  }
2081  tmp++;
2082  }
2083 
2084  if (i == 0) // all loop'd successfully
2085  {
2086  // should never occur to successfully get all zero'd data
2088  }
2089  }
2090  }
2091 
2092  // if everything succeeded, then (and only then) modify the device extension
2093  if (NT_SUCCESS(status))
2094  {
2095  DeviceExtension->DeviceAdditionalData.CachedInquiryData = tmpInquiry;
2096  DeviceExtension->DeviceAdditionalData.CachedInquiryDataByteCount = requestedInquiryTransferBytes;
2097  }
2098  else
2099  {
2100  FREE_POOL(tmpInquiry);
2101  }
2102 
2103  return status;
2104 }
2105 
2107 NTSTATUS
2108 DeviceGetMmcSupportInfo(
2109  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
2110  _Out_ PBOOLEAN IsMmcDevice
2111  )
2112 /*++
2113 
2114 Routine Description:
2115 
2116  check if the device is MMC capable.
2117 
2118 Arguments:
2119 
2120  DeviceExtension - device extension.
2121 
2122 Return Value:
2123 
2124  NTSTATUS.
2125  IsMmcDevice - TRUE (MMC capable); FALSE (not MMC device)
2126 
2127 --*/
2128 {
2129  NTSTATUS status;
2130  ULONG size;
2131  ULONG previouslyFailed;
2132 
2133  PAGED_CODE();
2134 
2135  *IsMmcDevice = FALSE;
2136 
2137  // read the registry in case the drive failed previously,
2138  // and a timeout is occurring.
2139  previouslyFailed = FALSE;
2140  DeviceGetParameter(DeviceExtension,
2143  &previouslyFailed);
2144 
2145  if (previouslyFailed)
2146  {
2147  SET_FLAG(DeviceExtension->DeviceAdditionalData.HackFlags, CDROM_HACK_BAD_GET_CONFIG_SUPPORT);
2148  }
2149 
2150  // read from the registry in case the drive reports bad profile lengths
2151  previouslyFailed = FALSE;
2152  DeviceGetParameter(DeviceExtension,
2155  &previouslyFailed);
2156 
2157  if (previouslyFailed)
2158  {
2159  SET_FLAG(DeviceExtension->DeviceAdditionalData.HackFlags, CDROM_HACK_BAD_VENDOR_PROFILES);
2160  }
2161 
2162  // check for the ProfileList feature to determine if the drive is MMC compliant
2163  // and set the "size" local variable to total GetConfig data size available.
2164  // NOTE: This will exit this function in some error paths.
2165  {
2166  GET_CONFIGURATION_HEADER localHeader = {0};
2167  ULONG usable = 0;
2168 
2169  status = DeviceGetConfiguration(DeviceExtension->Device,
2170  &localHeader,
2171  sizeof(GET_CONFIGURATION_HEADER),
2172  &usable,
2175 
2180  {
2181  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT,
2182  "GetConfiguration Failed (%x), device %p not mmc-compliant\n",
2183  status, DeviceExtension->DeviceObject
2184  ));
2185 
2186  previouslyFailed = TRUE;
2187  DeviceSetParameter( DeviceExtension,
2190  previouslyFailed);
2191 
2192  return STATUS_SUCCESS;
2193  }
2194  else if (!NT_SUCCESS(status))
2195  {
2196  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT,
2197  "GetConfiguration Failed, status %x -- defaulting to -ROM\n",
2198  status));
2199 
2200  return STATUS_SUCCESS;
2201  }
2202  else if (usable < sizeof(GET_CONFIGURATION_HEADER))
2203  {
2204  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT,
2205  "GetConfiguration Failed, returned only %x bytes!\n", usable));
2206  previouslyFailed = TRUE;
2207  DeviceSetParameter( DeviceExtension,
2210  previouslyFailed);
2211 
2212  return STATUS_SUCCESS;
2213  }
2214 
2215  size = (localHeader.DataLength[0] << 24) |
2216  (localHeader.DataLength[1] << 16) |
2217  (localHeader.DataLength[2] << 8) |
2218  (localHeader.DataLength[3] << 0) ;
2219 
2220 
2221  if ((size <= 4) || (size + 4 < size))
2222  {
2223  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT,
2224  "GetConfiguration Failed, claims MMC support but doesn't "
2225  "correctly return config length! (%x)\n",
2226  size
2227  ));
2228  previouslyFailed = TRUE;
2229  DeviceSetParameter( DeviceExtension,
2232  previouslyFailed);
2233 
2234  return STATUS_SUCCESS;
2235  }
2236  else if ((size % 4) != 0)
2237  {
2238  if ((size % 2) != 0)
2239  {
2240  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT,
2241  "GetConfiguration Failed, returned odd number of bytes %x!\n",
2242  size
2243  ));
2244  previouslyFailed = TRUE;
2245  DeviceSetParameter( DeviceExtension,
2248  previouslyFailed);
2249 
2250  return STATUS_SUCCESS;
2251  }
2252  else
2253  {
2254  if (TEST_FLAG(DeviceExtension->DeviceAdditionalData.HackFlags, CDROM_HACK_BAD_VENDOR_PROFILES))
2255  {
2256  // we've already caught this and ASSERT'd once, so don't do it again
2257  }
2258  else
2259  {
2260  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT,
2261  "GetConfiguration returned a size that is not per spec (%x bytes), this is probably because of a vendor specific data header with a size not divisible by 4.\n",
2262  size
2263  ));
2264  previouslyFailed = TRUE;
2265  DeviceSetParameter(DeviceExtension,
2268  previouslyFailed);
2269  }
2270  }
2271  }
2272 
2273  size += 4; // sizeof the datalength fields
2274  }
2275 
2276  *IsMmcDevice = TRUE;
2277 
2278  // This code doesn't handle total get config size over 64k
2279  NT_ASSERT( size <= MAXUSHORT );
2280 
2281  // Check for SCSI_GET_CONFIGURATION_REQUEST_TYPE_ONE support in the device.
2282  // NOTE: This will exit this function in some error paths.
2283  {
2284  ULONG featureSize = sizeof(GET_CONFIGURATION_HEADER)+sizeof(FEATURE_HEADER);
2285  ULONG usable = 0;
2286 
2288  NonPagedPoolNx,
2289  featureSize,
2291 
2292  if (configBuffer == NULL)
2293  {
2295  }
2296 
2297  // read the registry in case the drive failed previously,
2298  // and a timeout is occurring.
2299  previouslyFailed = FALSE;
2300  DeviceGetParameter( DeviceExtension,
2303  &previouslyFailed);
2304 
2305  if (previouslyFailed)
2306  {
2307  SET_FLAG(DeviceExtension->DeviceAdditionalData.HackFlags, CDROM_HACK_BAD_TYPE_ONE_GET_CONFIG);
2308  FREE_POOL(configBuffer);
2309  return STATUS_SUCCESS;
2310  }
2311 
2312  // Get only the config and feature header
2313  status = DeviceGetConfiguration(DeviceExtension->Device,
2314  configBuffer,
2315  featureSize,
2316  &usable,
2319 
2320  if (!NT_SUCCESS(status) || (usable < featureSize))
2321  {
2322  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT,
2323  "Type One GetConfiguration Failed. Usable buffer size: %d\n", usable));
2324  previouslyFailed = TRUE;
2325  }
2326  else
2327  {
2328  PFEATURE_HEADER featureHeader;
2329  ULONG totalAvailableBytes = 0;
2330  ULONG expectedAvailableBytes = 0;
2331 
2332  REVERSE_BYTES(&totalAvailableBytes, configBuffer->DataLength);
2334 
2335  featureHeader = (PFEATURE_HEADER) ((PUCHAR)configBuffer + sizeof(GET_CONFIGURATION_HEADER));
2336  expectedAvailableBytes = sizeof(GET_CONFIGURATION_HEADER) +
2337  sizeof(FEATURE_HEADER) +
2338  featureHeader->AdditionalLength;
2339 
2340  if (totalAvailableBytes > expectedAvailableBytes)
2341  {
2342  // Device is returning more than required size. Most likely the device
2343  // is returning TYPE ALL data. Set the flag to use TYPE ALL for TYPE ONE
2344  // requets
2345  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT,
2346  "Type One GetConfiguration Failed. "
2347  "Device returned %d bytes instead of %d bytes\n",
2348  size, featureSize));
2349 
2350  previouslyFailed = TRUE;
2351  }
2352  }
2353 
2354  FREE_POOL(configBuffer);
2355 
2356  if (previouslyFailed == TRUE)
2357  {
2358  DeviceSetParameter( DeviceExtension,
2361  previouslyFailed);
2362 
2363  SET_FLAG(DeviceExtension->DeviceAdditionalData.HackFlags, CDROM_HACK_BAD_TYPE_ONE_GET_CONFIG);
2364  }
2365  }
2366 
2367  return status;
2368 }
2369 
2370 
2372 NTSTATUS
2373 DeviceSetRawReadInfo(
2374  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
2375  )
2376 /*++
2377 
2378 Routine Description:
2379 
2380  This routine reads the CDROM capabilities mode page and save information
2381  in the device extension needed for raw reads.
2382  NOTE: this function is only valid for MMC device
2383 
2384 Arguments:
2385 
2386  DeviceExtension - device context
2387 
2388 Return Value:
2389 
2390  NTSTATUS
2391 
2392 --*/
2393 {
2395  PUCHAR buffer = NULL;
2396  ULONG count = 0;
2397 
2398  PAGED_CODE();
2399 
2400  // Check whether the device can return C2 error flag bits and the block
2401  // error byte. If so, save this info and fill in appropriate flag during
2402  // raw read requests.
2403 
2404  // Start by checking the GET_CONFIGURATION data
2405  {
2406  PFEATURE_DATA_CD_READ cdReadHeader = NULL;
2408 
2409  cdReadHeader = DeviceFindFeaturePage(DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBuffer,
2410  DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBufferSize,
2411  FeatureCdRead);
2412 
2413  if ((cdReadHeader != NULL) &&
2414  (cdReadHeader->Header.AdditionalLength >= additionalLength) &&
2415  (cdReadHeader->C2ErrorData)
2416  )
2417  {
2418  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2419  "DeviceSetRawReadInfo: FDO %p GET_CONFIG shows ability to read C2 error bits\n",
2420  DeviceExtension->DeviceObject
2421  ));
2422  DeviceExtension->DeviceAdditionalData.Mmc.ReadCdC2Pointers = TRUE; // Device returns C2 error info.
2423  }
2424  }
2425 
2426  // Unfortunately, the only way to check for the ability to read R-W subcode
2427  // information is via MODE_SENSE. Do so here, and check the C2 bit as well
2428  // in case the drive has a firmware bug where it fails to report this ability
2429  // in GET_CONFIG (which some drives do).
2430  for (count = 0; count < 6; count++)
2431  {
2432  SCSI_REQUEST_BLOCK srb = {0};
2433  PCDB cdb = (PCDB)srb.Cdb;
2434  ULONG bufferLength = 0;
2435 
2436  // Build the MODE SENSE CDB. Try 10-byte CDB first.
2437  if ((count/3) == 0)
2438  {
2440  sizeof(MODE_PARAMETER_HEADER10) +
2441  sizeof(MODE_PARAMETER_BLOCK);
2442 
2443  cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
2444  cdb->MODE_SENSE10.Dbd = 1;
2445  cdb->MODE_SENSE10.PageCode = MODE_PAGE_CAPABILITIES;
2446  cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(bufferLength >> 8);
2447  cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(bufferLength >> 0);
2448  srb.CdbLength = 10;
2449  }
2450  else
2451  {
2453  sizeof(MODE_PARAMETER_HEADER) +
2454  sizeof(MODE_PARAMETER_BLOCK);
2455 
2456  cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
2457  cdb->MODE_SENSE.Dbd = 1;
2458  cdb->MODE_SENSE.PageCode = MODE_PAGE_CAPABILITIES;
2459  cdb->MODE_SENSE.AllocationLength = (UCHAR)bufferLength;
2460  srb.CdbLength = 6;
2461  }
2462 
2463  // Set timeout value from device extension.
2464  srb.TimeOutValue = DeviceExtension->TimeOutValue;
2465 
2467 
2468  if (buffer == NULL)
2469  {
2470  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL,
2471  "DeviceSetRawReadInfo: cannot allocate "
2472  "buffer, so not setting raw read info for FDO %p\n",
2473  DeviceExtension->DeviceObject
2474  ));
2476  goto FnExit;
2477  }
2478 
2480 
2481  status = DeviceSendSrbSynchronously(DeviceExtension->Device,
2482  &srb,
2483  buffer,
2484  bufferLength,
2485  FALSE,
2486  NULL);
2487 
2488  if (NT_SUCCESS(status) ||
2489  (status == STATUS_DATA_OVERRUN) ||
2491  {
2492  PCDVD_CAPABILITIES_PAGE capabilities = NULL;
2493 
2494  // determine where the capabilities page really is
2495  if ((count/3) == 0)
2496  {
2498  capabilities = (PCDVD_CAPABILITIES_PAGE)(buffer +
2499  sizeof(MODE_PARAMETER_HEADER10) +
2500  (p->BlockDescriptorLength[0] * 256) +
2501  p->BlockDescriptorLength[1]);
2502  }
2503  else
2504  {
2506  capabilities = (PCDVD_CAPABILITIES_PAGE)(buffer +
2507  sizeof(MODE_PARAMETER_HEADER) +
2508  p->BlockDescriptorLength);
2509  }
2510 
2511  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2512  "DeviceSetRawReadInfo: FDO %p CDVD Capabilities buffer %p\n",
2513  DeviceExtension->DeviceObject,
2514  buffer
2515  ));
2516 
2517  if (capabilities->PageCode == MODE_PAGE_CAPABILITIES)
2518  {
2519  if (capabilities->C2Pointers)
2520  {
2521  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2522  "DeviceSetRawReadInfo: FDO %p supports C2 error bits in READ_CD command\n",
2523  DeviceExtension->DeviceObject
2524  ));
2525  DeviceExtension->DeviceAdditionalData.Mmc.ReadCdC2Pointers = TRUE;
2526  }
2527 
2528  if (capabilities->RWSupported)
2529  {
2530  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2531  "DeviceSetRawReadInfo: FDO %p supports raw subcode in READ_CD command\n",
2532  DeviceExtension->DeviceObject
2533  ));
2534  DeviceExtension->DeviceAdditionalData.Mmc.ReadCdSubCode = TRUE;
2535  }
2536 
2537  break;
2538  }
2539  }
2540 
2541  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
2542  "DeviceSetRawReadInfo: FDO %p failed %x byte mode sense, status %x\n",
2543  DeviceExtension->DeviceObject,
2544  (((count/3) == 0) ? 10 : 6),
2545  status
2546  ));
2547 
2548  FREE_POOL(buffer);
2549  }
2550 
2551  if (count == 6)
2552  {
2553  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
2554  "DeviceSetRawReadInfo: FDO %p couldn't get mode sense data\n",
2555  DeviceExtension->DeviceObject
2556  ));
2557  }
2558 
2559 FnExit:
2560 
2561  if (buffer)
2562  {
2563  FREE_POOL(buffer);
2564  }
2565 
2566  return status;
2567 }
2568 
2569 
2571 NTSTATUS
2572 DeviceInitializeDvd(
2573  _In_ WDFDEVICE Device
2574  )
2575 /*++
2576 
2577 Routine Description:
2578 
2579  This routine sets the region of DVD drive
2580  NOTE: this routine uses ScratchBuffer, it must be called after ScratchBuffer allocated.
2581 
2582 Arguments:
2583 
2584  Device - device object
2585 
2586 Return Value:
2587 
2588  NTSTATUS
2589 
2590 --*/
2591 
2592 {
2594  PCDROM_DEVICE_EXTENSION deviceExtension;
2595  PDVD_COPY_PROTECT_KEY copyProtectKey = NULL;
2596  PDVD_RPC_KEY rpcKey = NULL;
2597  ULONG bufferLen = 0;
2598  size_t bytesReturned;
2599 
2600  PAGED_CODE();
2601 
2602  deviceExtension = DeviceGetExtension(Device);
2603 
2604  // check to see if we have a DVD device
2605  if (deviceExtension->DeviceAdditionalData.DriveDeviceType != FILE_DEVICE_DVD)
2606  {
2607  return STATUS_SUCCESS;
2608  }
2609 
2610  // we got a DVD drive.
2611  bufferLen = DVD_RPC_KEY_LENGTH;
2613  bufferLen,
2615 
2616  if (copyProtectKey == NULL)
2617  {
2619  }
2620 
2621  // get the device region
2622  RtlZeroMemory (copyProtectKey, bufferLen);
2623  copyProtectKey->KeyLength = DVD_RPC_KEY_LENGTH;
2624  copyProtectKey->KeyType = DvdGetRpcKey;
2625 
2626  // perform IOCTL_DVD_READ_KEY
2627  status = DvdStartSessionReadKey(deviceExtension,
2629  NULL,
2630  copyProtectKey,
2632  copyProtectKey,
2634  &bytesReturned);
2635 
2636  if (NT_SUCCESS(status))
2637  {
2638  rpcKey = (PDVD_RPC_KEY)copyProtectKey->KeyData;
2639 
2640  // TypeCode of zero means that no region has been set.
2641  if (rpcKey->TypeCode == 0)
2642  {
2643  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP,
2644  "DVD Initialize (%p): must choose DVD region\n",
2645  Device));
2646  deviceExtension->DeviceAdditionalData.PickDvdRegion = 1;
2647 
2648  // set the device region code to be the same as region code on media.
2649  if (deviceExtension->DeviceAdditionalData.Mmc.IsCssDvd)
2650  {
2651  DevicePickDvdRegion(Device);
2652  }
2653  }
2654  }
2655 
2656  FREE_POOL(copyProtectKey);
2657 
2658  // return status of IOCTL_DVD_READ_KEY will be ignored.
2659  return STATUS_SUCCESS;
2660 }
2661 
2662 
2663 #if (NTDDI_VERSION >= NTDDI_WIN8)
2665 NTSTATUS
2666 DeviceIsPortable(
2667  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
2668  _Out_ PBOOLEAN IsPortable
2669  )
2670 /*++
2671 
2672 Routine Description:
2673 
2674  This routine checks if the volume is on a portable storage device.
2675 
2676 Arguments:
2677 
2678  DeviceExtension - device context
2679  IsPortable - device is portable
2680 
2681 Return Value:
2682 
2683  NTSTATUS.
2684 
2685 --*/
2686 
2687 {
2688  DEVPROP_BOOLEAN isInternal = DEVPROP_FALSE;
2689  BOOLEAN isPortable = FALSE;
2690  ULONG size = 0;
2693 
2694  PAGED_CODE();
2695 
2696  *IsPortable = FALSE;
2697 
2698  // Check to see if the underlying device object is in local machine container
2699  status = IoGetDevicePropertyData(DeviceExtension->LowerPdo,
2700  &DEVPKEY_Device_InLocalMachineContainer,
2701  0,
2702  0,
2703  sizeof(isInternal),
2704  &isInternal,
2705  &size,
2706  &type);
2707 
2708  if (!NT_SUCCESS(status))
2709  {
2710  goto Cleanup;
2711  }
2712 
2713  NT_ASSERT(size == sizeof(isInternal));
2715 
2716  // Volume is hot-pluggable if the disk pdo container id differs from that of root device
2717  if (isInternal == DEVPROP_TRUE)
2718  {
2719  goto Cleanup;
2720  }
2721 
2722  isPortable = TRUE;
2723 
2724  // Examine the bus type to ensure that this really is a fixed device
2725  if (DeviceExtension->DeviceDescriptor->BusType == BusTypeFibre ||
2726  DeviceExtension->DeviceDescriptor->BusType == BusTypeiScsi ||
2727  DeviceExtension->DeviceDescriptor->BusType == BusTypeRAID)
2728  {
2729  isPortable = FALSE;
2730  }
2731 
2732  *IsPortable = isPortable;
2733 
2734 Cleanup:
2735 
2736  return status;
2737 }
2738 #endif
2739 
2740 
2741 #pragma warning(pop) // un-sets any local warning changes
2742 
#define STATUS_OBJECT_NAME_COLLISION
Definition: udferr_usr.h:150
struct _CDVD_CAPABILITIES_PAGE CDVD_CAPABILITIES_PAGE
MODE_PARAMETER_HEADER ParameterListHeader
Definition: cdrw_hw.h:2536
#define FDO_HACK_CANNOT_LOCK_MEDIA
Definition: cdromp.h:133
#define max(a, b)
Definition: svc.c:63
#define STATUS_NO_MEDIA_IN_DEVICE
Definition: udferr_usr.h:141
enum _STORAGE_PROPERTY_ID STORAGE_PROPERTY_ID
CDROM_SCAN_FOR_SPECIAL_INFO CdRomBadItems[]
Definition: data.c:100
* PSTORAGE_DESCRIPTOR_HEADER
Definition: ntddstor.h:560
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
#define IOCTL_SCSI_GET_ADDRESS
Definition: scsi_port.h:52
ULONG SrbFlags
Definition: srb.h:252
struct png_info_def **typedef void(__cdecl typeof(png_destroy_read_struct))(struct png_struct_def **
Definition: typeof.h:49
_Must_inspect_result_ _In_ WDFIORESLIST _In_ PIO_RESOURCE_DESCRIPTOR Descriptor
Definition: wdfresource.h:339
VOID DeviceSetMediaChangeStateEx(_In_ PCDROM_DEVICE_EXTENSION DeviceExtension, _In_ MEDIA_CHANGE_DETECTION_STATE NewState, _Inout_opt_ PMEDIA_CHANGE_DETECTION_STATE OldState)
Definition: autorun.c:751
_In_ CDROM_SCAN_FOR_SPECIAL_INFO _In_ PCDROM_SCAN_FOR_SPECIAL_HANDLER Function
Definition: cdrom.h:1154
PVOID OriginalRequest
Definition: srb.h:258
UCHAR Cdb[16]
Definition: srb.h:271
BOOLEAN IsInitialized
Definition: cdrom.h:464
#define CDROM_NON_MMC_DRIVE_NAME
Definition: cdrom.h:756
#define STATUS_DATA_OVERRUN
Definition: udferr_usr.h:152
USHORT MaximumLength
Definition: env_spec_w32.h:370
EVT_WDF_REQUEST_COMPLETION_ROUTINE DeviceReleaseQueueCompletion
Definition: cdrom.h:1052
PCONFIGURATION_INFORMATION NTAPI IoGetConfigurationInformation(VOID)
Definition: iorsrce.c:830
#define SRB_FLAGS_FREE_SENSE_BUFFER
Definition: srb.h:398
#define PLUGPLAY_REGKEY_DEVICE
Definition: iofuncs.h:2786
BOOLEAN DeviceHotplug
Definition: imports.h:248
PCDROM_PRIVATE_FDO_DATA PrivateFdoData
Definition: cdrom.h:605
#define KEY_READ
Definition: nt_native.h:1023
#define TRUE
Definition: types.h:120
#define SCSIOP_MODE_SENSE
Definition: cdrw_hw.h:896
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define CDROM_SUBKEY_NAME
Definition: cdrom.h:754
NTSTRSAFEVAPI RtlStringCchPrintfW(_Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest, _In_ size_t cchDest, _In_ _Printf_format_string_ NTSTRSAFE_PCWSTR pszFormat,...)
Definition: ntstrsafe.h:1110
GLuint GLuint GLsizei count
Definition: gl.h:1545
CDROM_DATA DeviceAdditionalData
Definition: cdrom.h:598
WDFIOTARGET IoTarget
Definition: cdrom.h:476
unsigned char * PUCHAR
Definition: retypes.h:3
ULONG DataTransferLength
Definition: srb.h:253
#define CLASS_PERF_RESTORE_MINIMUM
Definition: cdromp.h:129
struct _MODE_PARAMETER_BLOCK MODE_PARAMETER_BLOCK
Definition: cdrw_hw.h:28
#define STATUS_OBJECT_NAME_EXISTS
Definition: ntstatus.h:114
LONG NTSTATUS
Definition: precomp.h:26
struct _FEATURE_HEADER * PFEATURE_HEADER
#define REVERSE_BYTES(Destination, Source)
Definition: scsi.h:3465
#define _Outptr_
Definition: no_sal2.h:262
GLdouble GLdouble t
Definition: gl.h:2047
#define STATUS_INVALID_DEVICE_REQUEST
Definition: udferr_usr.h:138
struct _CDB::_MODE_SENSE10 MODE_SENSE10
UCHAR CdbLength
Definition: srb.h:250
GLuint buffer
Definition: glext.h:5915
#define DO_SYSTEM_SYSTEM_PARTITION
_In_opt_ PVOID _In_ ULONG bufferLength
Definition: wdfdriver.h:107
#define SRB_FUNCTION_CLAIM_DEVICE
Definition: srb.h:308
PDEVICE_LIST DeviceList
Definition: utils.c:27
#define DEVPROP_TYPE_BOOLEAN
Definition: devpropdef.h:46
uint16_t * PWCHAR
Definition: typedefs.h:56
if(dx==0 &&dy==0)
Definition: linetemp.h:174
char * LPSTR
Definition: xmlstorage.h:182
#define TRACE_LEVEL_INFORMATION
Definition: storswtr.h:29
ULONG DEVPROPTYPE
Definition: devpropdef.h:24
ULONG TimeOutValue
Definition: srb.h:254
ULONG PickDvdRegion
Definition: cdrom.h:354
NTSTATUS DeviceErrorHandlerForMmc(_In_ PCDROM_DEVICE_EXTENSION DeviceExtension, _In_ PSCSI_REQUEST_BLOCK Srb, _Inout_ PNTSTATUS Status, _Inout_ PBOOLEAN Retry)
Definition: sense.c:87
UCHAR SrbStatus
Definition: srb.h:243
#define SENSE_BUFFER_SIZE
Definition: cdrw_hw.h:1183
#define CLASSP_REG_HACK_VALUE_NAME
Definition: cdromp.h:122
#define WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(_attributes, _contexttype)
Definition: wdfobject.h:170
BOOLEAN IsWriter
Definition: cdrom.h:249
FORCEINLINE WDFDRIVER WdfGetDriver(VOID)
Definition: wdfdriver.h:194
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define STATUS_IO_DEVICE_ERROR
Definition: udferr_usr.h:179
#define FILE_DEVICE_CD_ROM
Definition: winioctl.h:108
#define STATUS_DEVICE_PROTOCOL_ERROR
Definition: ntstatus.h:623
FxRequest * request
BOOLEAN MediaHotplug
Definition: imports.h:247
#define CLASSP_REG_PERF_RESTORE_VALUE_NAME
Definition: cdromp.h:125
#define CDROM_TAG_PRIVATE_DATA
Definition: cdromp.h:173
* PSTORAGE_DEVICE_DESCRIPTOR
Definition: ntddstor.h:576
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
struct _CDVD_CAPABILITIES_PAGE * PCDVD_CAPABILITIES_PAGE
#define CLASSP_REG_SUBKEY_NAME
Definition: cdromp.h:120
struct _DVD_RPC_KEY * PDVD_RPC_KEY
#define FALSE
Definition: types.h:117
#define FREE_POOL(_PoolPtr)
Definition: cdrom.h:782
long LONG
Definition: pedump.c:60
#define TRACE_LEVEL_FATAL
Definition: storswtr.h:26
#define FILE_REMOVABLE_MEDIA
Definition: nt_native.h:807
NTSTATUS DeviceErrorHandlerForHitachiGD2000(_In_ PCDROM_DEVICE_EXTENSION DeviceExtension, _In_ PSCSI_REQUEST_BLOCK Srb, _Inout_ PNTSTATUS Status, _Inout_ PBOOLEAN Retry)
Definition: sense.c:361
#define CDROM_HACK_BAD_GET_CONFIG_SUPPORT
Definition: cdrom.h:96
#define SCSI_CDROM_OPC_TIMEOUT
Definition: cdrom.h:688
descriptor
Definition: scsi.h:3951
#define CDROM_HACK_BAD_VENDOR_PROFILES
Definition: cdrom.h:100
unsigned char BOOLEAN
#define SCSIOP_MODE_SENSE10
Definition: cdrw_hw.h:946
#define DO_SYSTEM_BOOT_PARTITION
Definition: env_spec_w32.h:400
#define SRB_FUNCTION_RELEASE_DEVICE
Definition: srb.h:313
union _CDB * PCDB
#define _Out_
Definition: no_sal2.h:160
#define CLEAR_FLAG(Flags, Bit)
Definition: cdrom.h:1494
_In_ ULONG _In_opt_ WDFREQUEST _In_opt_ PVOID _In_ size_t _In_ PVOID _In_ size_t _Out_ size_t * DataLength
Definition: cdrom.h:1437
struct _MODE_PARAMETER_HEADER * PMODE_PARAMETER_HEADER
#define C_ASSERT(e)
Definition: intsafe.h:71
FORCEINLINE VOID WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(_Out_ PWDF_MEMORY_DESCRIPTOR Descriptor, _In_ PVOID Buffer, _In_ ULONG BufferLength)
Definition: wdfmemory.h:102
#define CDROM_HACK_INVALID_FLAGS
Definition: cdrom.h:105
#define CDROM_TAG_DESCRIPTOR
Definition: cdrom.h:730
const char * LPCSTR
Definition: xmlstorage.h:183
void * PVOID
Definition: retypes.h:9
#define DEV_SAFE_START_UNIT
Definition: cdrom.h:139
_IRQL_requires_max_(_IRQL_requires_max_() VOIDDeviceScanSpecialDevices(_In_ PCDROM_DEVICE_EXTENSION DeviceExtension) APC_LEVEL)
Definition: init.c:38
struct _CDB::_MODE_SELECT MODE_SELECT
#define TEST_FLAG(Flags, Bit)
Definition: cdrom.h:1495
struct _CDB::_MODE_SENSE MODE_SENSE
UCHAR AdditionalLength
Definition: ntddmmc.h:34
UCHAR additionalLength
Definition: scsi.h:3943
#define CDROM_TAG_GET_CONFIG
Definition: cdrom.h:728
#define SCSIOP_INQUIRY
Definition: cdrw_hw.h:888
#define CDROM_HACK_TOSHIBA_SD_W1101
Definition: cdrom.h:92
#define CDROM_TYPE_ONE_GET_CONFIG_NAME
Definition: cdrom.h:757
#define DEVPROP_TYPE_EMPTY
Definition: devpropdef.h:29
#define IOCTL_STORAGE_QUERY_PROPERTY
Definition: ntddstor.h:178
GLsizeiptr size
Definition: glext.h:5919
BOOLEAN WriteCacheEnableOverride
Definition: imports.h:249
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define CLASSP_REG_WRITE_CACHE_VALUE_NAME
Definition: cdromp.h:124
UCHAR Function
Definition: srb.h:242
#define DECLARE_CONST_UNICODE_STRING(_variablename, _string)
Definition: wdfcore.h:161
struct _MODE_PARAMETER_HEADER10 * PMODE_PARAMETER_HEADER10
enum _STORAGE_PROPERTY_ID * PSTORAGE_PROPERTY_ID
#define RTL_SIZEOF_THROUGH_FIELD(type, field)
Definition: ntbasedef.h:672
USHORT Length
Definition: srb.h:241
#define FDO_HACK_INVALID_FLAGS
Definition: cdromp.h:141
#define SRB_STATUS_DATA_OVERRUN
Definition: srb.h:349
#define FILE_PORTABLE_DEVICE
Definition: winternl.h:1855
struct _SCSI_REQUEST_BLOCK SCSI_REQUEST_BLOCK
#define HITACHI_MODE_DATA_SIZE
Definition: cdrom.c:172
VOID(* PCDROM_SCAN_FOR_SPECIAL_HANDLER)(_In_ PCDROM_DEVICE_EXTENSION DeviceExtension, _In_ ULONG_PTR Data)
Definition: cdrom.h:775
#define CDROM_TAG_STRINGS
Definition: cdrom.h:743
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
#define DEVPROP_TRUE
Definition: devpropdef.h:66
#define MINIMUM_CDROM_INQUIRY_SIZE
Definition: ntddcdrm.h:128
#define MODE_PAGE_CAPABILITIES
Definition: cdrw_hw.h:854
UCHAR BlockLength[3]
Definition: cdrw_hw.h:2531
DVD_KEY_TYPE KeyType
Definition: ntddcdvd.h:178
unsigned char UCHAR
Definition: xmlstorage.h:181
_Null_terminated_ wchar_t * NTSTRSAFE_PWSTR
Definition: ntstrsafe.h:58
char * PBOOLEAN
Definition: retypes.h:11
static const WCHAR L[]
Definition: oid.c:1250
#define DO_SYSTEM_CRITICAL_PARTITION
struct _CDROM_PRIVATE_FDO_DATA::@1020 Perf
#define VOID
Definition: acefi.h:82
#define SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL
Definition: ntddmmc.h:15
DEVICE_TYPE DriveDeviceType
Definition: cdrom.h:388
#define PAGE_SIZE
Definition: env_spec_w32.h:49
#define SCSI_GET_CONFIGURATION_REQUEST_TYPE_ONE
Definition: ntddmmc.h:17
#define IOCTL_DVD_READ_KEY
Definition: cdrw_usr.h:160
struct _FEATURE_DATA_CD_READ FEATURE_DATA_CD_READ
static const WCHAR Cleanup[]
Definition: register.c:80
#define PASSIVE_LEVEL
Definition: env_spec_w32.h:693
_Must_inspect_result_ _In_ WDFDEVICE Device
Definition: wdfchildlist.h:474
UCHAR AdditionalLength
Definition: cdrw_hw.h:1122
#define DVD_TAG_RPC2_CHECK
Definition: cdrom.h:748
#define IOCTL_SCSI_EXECUTE_IN
Definition: cdrw_hw.h:1451
#define CDROM_TAG_MODE_DATA
Definition: cdrom.h:737
enum _FEATURE_NUMBER FEATURE_NUMBER
#define TRACE_LEVEL_ERROR
Definition: storswtr.h:27
#define TRACE_LEVEL_WARNING
Definition: storswtr.h:28
#define IOCTL_SCSI_EXECUTE_NONE
Definition: cdrw_hw.h:1453
#define _In_
Definition: no_sal2.h:158
FORCEINLINE VOID WDF_OBJECT_ATTRIBUTES_INIT(_Out_ PWDF_OBJECT_ATTRIBUTES Attributes)
Definition: wdfobject.h:147
MODE_PARAMETER_BLOCK ParameterListBlock
Definition: cdrw_hw.h:2537
_In_ BOOLEAN Release
Definition: cdrom.h:920
STORAGE_HOTPLUG_INFO HotplugInfo
Definition: cdromp.h:343
SCSI_ADDRESS ScsiAddress
Definition: cdrom.h:521
#define CDROM_HACK_DEC_RRD
Definition: cdrom.h:88
#define STATUS_BUFFER_OVERFLOW
Definition: shellext.h:66
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define RTL_NUMBER_OF(x)
Definition: RtlRegistry.c:12
#define FILE_DEVICE_DVD
Definition: winioctl.h:157
struct _GET_CONFIGURATION_HEADER GET_CONFIGURATION_HEADER
struct _DVD_COPY_PROTECT_KEY * PDVD_COPY_PROTECT_KEY
CHAR DEVPROP_BOOLEAN
Definition: devpropdef.h:64
WDFOBJECT ParentObject
Definition: wdfobject.h:130
enum _DEVICE_REMOVAL_POLICY DEVICE_REMOVAL_POLICY
unsigned int * PULONG
Definition: retypes.h:1
#define min(a, b)
Definition: monoChain.cc:55
#define NULL
Definition: types.h:112
#define CDROM_NON_MMC_VENDOR_SPECIFIC_PROFILE
Definition: cdrom.h:758
#define STATUS_IO_TIMEOUT
Definition: udferr_usr.h:163
#define WDF_NO_OBJECT_ATTRIBUTES
Definition: wdftypes.h:105
#define MAXUSHORT
Definition: typedefs.h:83
Definition: tftpd.h:85
#define CdromMmcUpdateRequired
Definition: cdrom.h:242
CDROM_MMC_EXTENSION Mmc
Definition: cdrom.h:341
NTSTATUS NTAPI DeviceEvtSelfManagedIoInit(_In_ WDFDEVICE Device)
Definition: init.c:222
#define CLASSP_REG_REMOVAL_POLICY_VALUE_NAME
Definition: cdromp.h:126
#define CDROM_HACK_HITACHI_GD_2000
Definition: cdrom.h:91
FEATURE_HEADER Header
Definition: ntddmmc.h:197
_In_ PSTORAGE_PROPERTY_ID PropertyId
Definition: cdrom.h:932
unsigned int ULONG
Definition: retypes.h:1
#define DVD_RPC_KEY_LENGTH
Definition: cdrw_usr.h:1597
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define CDROM_HACK_BAD_TYPE_ONE_GET_CONFIG
Definition: cdrom.h:99
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
PDEVICE_OBJECT DeviceObject
Definition: cdrom.h:493
#define CDROM_TAG_SENSE_INFO
Definition: cdrom.h:735
#define STATUS_SUCCESS
Definition: shellext.h:65
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
#define DEVPROP_FALSE
Definition: devpropdef.h:67
#define CDROM_HACK_FUJITSU_FMCD_10x
Definition: cdrom.h:89
UNICODE_STRING MountedDeviceInterfaceName
Definition: cdrom.h:536
_In_ ULONG_PTR HackFlags
Definition: cdrom.h:983
GLfloat GLfloat p
Definition: glext.h:8902
BOOLEAN MediaRemovable
Definition: imports.h:246
static SERVICE_STATUS status
Definition: service.c:31
BOOLEAN IsCssDvd
Definition: cdrom.h:252
CDROM_SCAN_FOR_SPECIAL_INFO CdromHackItems[]
Definition: data.c:44
#define APC_LEVEL
Definition: env_spec_w32.h:695
#define CDROM_TAG_INQUIRY
Definition: cdrom.h:736
#define SET_FLAG(Flags, Bit)
Definition: cdrom.h:1493
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
struct _STORAGE_HOTPLUG_INFO STORAGE_HOTPLUG_INFO
UCHAR AsByte[16]
Definition: scsi.h:1988
#define FILE_READ_ONLY_DEVICE
Definition: nt_native.h:808
UCHAR TypeCode
Definition: scsi.h:2925
#define PAGED_CODE()
#define SCSIOP_MODE_SELECT
Definition: cdrw_hw.h:891
#define NT_ASSERT
Definition: rtlfuncs.h:3312
Definition: ps.c:97