ReactOS  0.4.15-dev-2355-gaf9df93
common.c
Go to the documentation of this file.
1 /*++
2 
3 Copyright (C) Microsoft Corporation. All rights reserved.
4 
5 Module Name:
6 
7  common.c
8 
9 Abstract:
10 
11  shared private routines for cdrom.sys
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 
29 #include "cdrom.h"
30 #include "scratch.h"
31 
32 
33 #ifdef DEBUG_USE_WPP
34 #include "common.tmh"
35 #endif
36 
37 #ifdef ALLOC_PRAGMA
38 
39 #pragma alloc_text(PAGE, DeviceGetParameter)
40 #pragma alloc_text(PAGE, DeviceSetParameter)
41 #pragma alloc_text(PAGE, DeviceSendSrbSynchronously)
42 #pragma alloc_text(PAGE, DevicePickDvdRegion)
43 #pragma alloc_text(PAGE, StringsAreMatched)
44 #pragma alloc_text(PAGE, PerformEjectionControl)
45 #pragma alloc_text(PAGE, DeviceFindFeaturePage)
46 #pragma alloc_text(PAGE, DevicePrintAllFeaturePages)
47 #pragma alloc_text(PAGE, DeviceRegisterInterface)
48 #pragma alloc_text(PAGE, DeviceRestoreDefaultSpeed)
49 #pragma alloc_text(PAGE, DeviceSendRequestSynchronously)
50 #pragma alloc_text(PAGE, MediaReadCapacity)
51 #pragma alloc_text(PAGE, MediaReadCapacityDataInterpret)
52 #pragma alloc_text(PAGE, DeviceRetrieveModeSenseUsingScratch)
53 #pragma alloc_text(PAGE, ModeSenseFindSpecificPage)
54 #pragma alloc_text(PAGE, DeviceUnlockExclusive)
55 
56 #endif
57 
58 LPCSTR LockTypeStrings[] = {"Simple",
59  "Secure",
60  "Internal"
61  };
62 
63 VOID
65  _In_ WDFREQUEST Request
66  )
67 {
68  PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(Request);
70 
72 
73  requestContext->TimeReceived = temp;
74 
75  return;
76 }
77 
78 VOID
80  _In_ WDFREQUEST Request
81  )
82 {
83  PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(Request);
85 
87 
88  if (requestContext->TimeSentDownFirstTime.QuadPart == 0)
89  {
90  requestContext->TimeSentDownFirstTime = temp;
91  }
92 
93  requestContext->TimeSentDownLasttTime = temp;
94 
95  if (requestContext->OriginalRequest != NULL)
96  {
97  PCDROM_REQUEST_CONTEXT originalRequestContext = RequestGetContext(requestContext->OriginalRequest);
98 
99  if (originalRequestContext->TimeSentDownFirstTime.QuadPart == 0)
100  {
101  originalRequestContext->TimeSentDownFirstTime = temp;
102  }
103 
104  originalRequestContext->TimeSentDownLasttTime = temp;
105  }
106 
107  return;
108 }
109 
110 VOID
112  _In_ WDFREQUEST Request
113  )
114 /*
115 Routine Description:
116 
117  This function is used to clean SentTime fields in reusable request context.
118 
119 Arguments:
120  Request -
121 
122 Return Value:
123  N/A
124 
125 */
126 {
127  PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(Request);
128 
129  requestContext->TimeSentDownFirstTime.QuadPart = 0;
130  requestContext->TimeSentDownLasttTime.QuadPart = 0;
131 
132  return;
133 }
134 
136 VOID
137 DeviceGetParameter(
138  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
141  _Inout_ PULONG ParameterValue // also default value
142  )
143 /*++
144 Routine Description:
145 
146  retrieve device parameter from registry.
147 
148 Arguments:
149 
150  DeviceExtension - device context.
151 
152  SubkeyName - name of subkey
153 
154  ParameterName - the registry parameter to be retrieved
155 
156 Return Value:
157 
158  ParameterValue - registry value retrieved
159 
160 --*/
161 {
163  WDFKEY rootKey = NULL;
164  WDFKEY subKey = NULL;
165  UNICODE_STRING registrySubKeyName;
166  UNICODE_STRING registryValueName;
167  ULONG defaultParameterValue;
168 
169  PAGED_CODE();
170 
171  RtlInitUnicodeString(&registryValueName, ParameterName);
172 
173  if (SubkeyName != NULL)
174  {
175  RtlInitUnicodeString(&registrySubKeyName, SubkeyName);
176  }
177 
178  // open the hardware key
179  status = WdfDeviceOpenRegistryKey(DeviceExtension->Device,
181  KEY_READ,
183  &rootKey);
184 
185  // open the sub key
186  if (NT_SUCCESS(status) && (SubkeyName != NULL))
187  {
188  status = WdfRegistryOpenKey(rootKey,
189  &registrySubKeyName,
190  KEY_READ,
192  &subKey);
193 
194  if (!NT_SUCCESS(status))
195  {
196  WdfRegistryClose(rootKey);
197  rootKey = NULL;
198  }
199  }
200 
201  if (NT_SUCCESS(status) && (rootKey != NULL))
202  {
203  defaultParameterValue = *ParameterValue;
204 
205  status = WdfRegistryQueryULong((subKey != NULL) ? subKey : rootKey,
206  &registryValueName,
208 
209  if (!NT_SUCCESS(status))
210  {
211  *ParameterValue = defaultParameterValue; // use default value
212  }
213  }
214 
215  // close what we open
216  if (subKey != NULL)
217  {
218  WdfRegistryClose(subKey);
219  subKey = NULL;
220  }
221 
222  if (rootKey != NULL)
223  {
224  WdfRegistryClose(rootKey);
225  rootKey = NULL;
226  }
227 
228  // Windows 2000 SP3 uses the driver-specific key, so look in there
229  if (!NT_SUCCESS(status))
230  {
231  // open the software key
232  status = WdfDeviceOpenRegistryKey(DeviceExtension->Device,
234  KEY_READ,
236  &rootKey);
237 
238  // open the sub key
239  if (NT_SUCCESS(status) && (SubkeyName != NULL))
240  {
241  status = WdfRegistryOpenKey(rootKey,
242  &registrySubKeyName,
243  KEY_READ,
245  &subKey);
246 
247  if (!NT_SUCCESS(status))
248  {
249  WdfRegistryClose(rootKey);
250  rootKey = NULL;
251  }
252  }
253 
254  if (NT_SUCCESS(status) && (rootKey != NULL))
255  {
256  defaultParameterValue = *ParameterValue;
257 
258  status = WdfRegistryQueryULong((subKey != NULL) ? subKey : rootKey,
259  &registryValueName,
261 
262  if (!NT_SUCCESS(status))
263  {
264  *ParameterValue = defaultParameterValue; // use default value
265  }
266  else
267  {
268  // Migrate the value over to the device-specific key
269  DeviceSetParameter(DeviceExtension, SubkeyName, ParameterName, *ParameterValue);
270  }
271  }
272 
273  // close what we open
274  if (subKey != NULL)
275  {
276  WdfRegistryClose(subKey);
277  subKey = NULL;
278  }
279 
280  if (rootKey != NULL)
281  {
282  WdfRegistryClose(rootKey);
283  rootKey = NULL;
284  }
285  }
286 
287  return;
288 
289 } // end DeviceetParameter()
290 
291 
293 NTSTATUS
294 DeviceSetParameter(
295  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
299  )
300 /*++
301 Routine Description:
302 
303  set parameter to registry.
304 
305 Arguments:
306 
307  DeviceExtension - device context.
308 
309  SubkeyName - name of subkey
310 
311  ParameterName - the registry parameter to be retrieved
312 
313  ParameterValue - registry value to be set
314 
315 Return Value:
316  NTSTATUS
317 
318 --*/
319 {
321  WDFKEY rootKey = NULL;
322  WDFKEY subKey = NULL;
323  UNICODE_STRING registrySubKeyName;
324  UNICODE_STRING registryValueName;
325 
326  PAGED_CODE();
327 
328  RtlInitUnicodeString(&registryValueName, ParameterName);
329 
330  if (SubkeyName != NULL)
331  {
332  RtlInitUnicodeString(&registrySubKeyName, SubkeyName);
333  }
334 
335  // open the hardware key
336  status = WdfDeviceOpenRegistryKey(DeviceExtension->Device,
340  &rootKey);
341 
342  // open the sub key
343  if (NT_SUCCESS(status) && (SubkeyName != NULL))
344  {
345  status = WdfRegistryOpenKey(rootKey,
346  &registrySubKeyName,
349  &subKey);
350 
351  if (!NT_SUCCESS(status))
352  {
353  WdfRegistryClose(rootKey);
354  rootKey = NULL;
355  }
356  }
357 
358  if (NT_SUCCESS(status) && (rootKey != NULL))
359  {
360  status = WdfRegistryAssignULong((subKey != NULL) ? subKey : rootKey,
361  &registryValueName,
363  }
364 
365  // close what we open
366  if (subKey != NULL)
367  {
368  WdfRegistryClose(subKey);
369  subKey = NULL;
370  }
371 
372  if (rootKey != NULL)
373  {
374  WdfRegistryClose(rootKey);
375  rootKey = NULL;
376  }
377 
378  return status;
379 
380 } // end DeviceSetParameter()
381 
382 
384 NTSTATUS
385 DeviceSendRequestSynchronously(
386  _In_ WDFDEVICE Device,
387  _In_ WDFREQUEST Request,
389  )
390 /*++
391 Routine Description:
392 
393  send a request to lower driver synchronously.
394 
395 Arguments:
396 
397  Device - device object.
398 
399  Request - request object
400 
401  RequestFormated - if the request is already formatted, will no do it in this function
402 
403 Return Value:
404  NTSTATUS
405 
406 --*/
407 {
409  PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device);
410  BOOLEAN requestCancelled = FALSE;
411  PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(Request);
412 
413  PAGED_CODE();
414 
415  if (!RequestFormated)
416  {
417  // set request up for sending down
418  WdfRequestFormatRequestUsingCurrentType(Request);
419  }
420 
421  // get cancellation status for the original request
422  if (requestContext->OriginalRequest != NULL)
423  {
424  requestCancelled = WdfRequestIsCanceled(requestContext->OriginalRequest);
425  }
426 
427  if (!requestCancelled)
428  {
429  status = RequestSend(deviceExtension,
430  Request,
431  deviceExtension->IoTarget,
433  NULL);
434  }
435  else
436  {
438  }
439 
440  return status;
441 }
442 
443 
445 NTSTATUS
446 DeviceSendSrbSynchronously(
447  _In_ WDFDEVICE Device,
452  _In_opt_ WDFREQUEST OriginalRequest
453  )
454 /*++
455 Routine Description:
456 
457  Send a SRB structure to lower driver synchronously.
458 
459  Process of this function:
460  1. Allocate SenseBuffer; Create Request; Allocate MDL
461  2. Do following loop if necessary
462  2.1 Reuse Request
463  2.2 Format Srb, Irp
464  2.3 Send Request
465  2.4 Error Intepret and retry decision making.
466  3. Release all allocated resosurces.
467 
468 Arguments:
469 
470  Device - device object.
471 
472  Request - request object
473 
474  RequestFormated - if the request is already formatted, will no do it in this function
475 
476 Return Value:
477  NTSTATUS
478 
479 NOTE:
480 The caller needs to setup following fields before calling this routine.
481  srb.CdbLength
482  srb.TimeOutValue
483  cdb
484 
485 BufferLength and WriteToDevice to control the data direction of the device
486  BufferLength = 0: No data transfer
487  BufferLenth != 0 && !WriteToDevice: get data from device
488  BufferLenth != 0 && WriteToDevice: send data to device
489 --*/
490 {
492  PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device);
493  PCDROM_PRIVATE_FDO_DATA fdoData = deviceExtension->PrivateFdoData;
495  ULONG retryCount = 0;
496  BOOLEAN retry = FALSE;
497  ULONG ioctlCode = 0;
498  WDFREQUEST request = NULL;
499  PIRP irp = NULL;
500  PIO_STACK_LOCATION nextStack = NULL;
501  PMDL mdlAddress = NULL;
502  BOOLEAN memoryLocked = FALSE;
503  WDF_OBJECT_ATTRIBUTES attributes;
504  PZERO_POWER_ODD_INFO zpoddInfo = deviceExtension->ZeroPowerODDInfo;
505 
506  PAGED_CODE();
507 
508  // NOTE: This code is only pagable because we are not freezing
509  // the queue. Allowing the queue to be frozen from a pagable
510  // routine could leave the queue frozen as we try to page in
511  // the code to unfreeze the queue. The result would be a nice
512  // case of deadlock. Therefore, since we are unfreezing the
513  // queue regardless of the result, just set the NO_FREEZE_QUEUE
514  // flag in the SRB.
516 
517  //1. allocate SenseBuffer and initiate Srb common fields
518  // these fields will not be changed by lower driver.
519  {
520  // Write length to SRB.
521  Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
522  Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
523  Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
524 
525  // Sense buffer is in aligned nonpaged pool.
526  senseInfoBuffer = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
529 
530  if (senseInfoBuffer == NULL)
531  {
533 
534  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
535  "DeviceSendSrbSynchronously: Can't allocate MDL\n"));
536 
537  goto Exit;
538  }
539 
540  Srb->SenseInfoBuffer = senseInfoBuffer;
541  Srb->DataBuffer = BufferAddress;
542 
543  // set timeout value to default value if it's not specifically set by caller.
544  if (Srb->TimeOutValue == 0)
545  {
546  Srb->TimeOutValue = deviceExtension->TimeOutValue;
547  }
548  }
549 
550  //2. Create Request object
551  {
554 
555  status = WdfRequestCreate(&attributes,
556  deviceExtension->IoTarget,
557  &request);
558 
559  if (!NT_SUCCESS(status))
560  {
561  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
562  "DeviceSendSrbSynchronously: Can't create request: %lx\n",
563  status));
564 
565  goto Exit;
566  }
567 
568  irp = WdfRequestWdmGetIrp(request);
569  }
570 
571  // 3. Build an MDL for the data buffer and stick it into the irp.
572  if (BufferAddress != NULL)
573  {
574  mdlAddress = IoAllocateMdl( BufferAddress,
575  BufferLength,
576  FALSE,
577  FALSE,
578  irp );
579  if (mdlAddress == NULL)
580  {
582 
583  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
584  "DeviceSendSrbSynchronously: Can't allocate MDL\n"));
585 
586  goto Exit;
587  }
588 
589  _SEH2_TRY
590  {
591  MmProbeAndLockPages(mdlAddress,
592  KernelMode,
594  }
596  {
598 
599  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
600  "DeviceSendSrbSynchronously: Exception %lx locking buffer\n", status));
601 
602  _SEH2_YIELD(goto Exit);
603  }
604  _SEH2_END;
605 
606  memoryLocked = TRUE;
607  }
608 
609  // 4. Format Srb, Irp; Send request and retry when necessary
610  do
611  {
612  // clear the control variable.
613  retry = FALSE;
614 
615  // 4.1 reuse the request object; set originalRequest field.
616  {
618  PCDROM_REQUEST_CONTEXT requestContext = NULL;
619 
620  // deassign the MdlAddress, this is the value we assign explicitly.
621  // doing this can prevent WdfRequestReuse to release the Mdl unexpectly.
622  if (irp->MdlAddress)
623  {
624  irp->MdlAddress = NULL;
625  }
626 
630 
631  status = WdfRequestReuse(request, &params);
632 
633  if (!NT_SUCCESS(status))
634  {
635  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
636  "DeviceSendSrbSynchronously: WdfRequestReuse failed, %!STATUS!\n",
637  status));
638  // exit the loop.
639  break;
640  }
641 
642  // WDF requests to format the request befor sending it
643  status = WdfIoTargetFormatRequestForInternalIoctlOthers(deviceExtension->IoTarget,
644  request,
645  ioctlCode,
646  NULL, NULL,
647  NULL, NULL,
648  NULL, NULL);
649 
650  if (!NT_SUCCESS(status))
651  {
652  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
653  "DeviceSendSrbSynchronously: WdfIoTargetFormatRequestForInternalIoctlOthers failed, %!STATUS!\n",
654  status));
655  // exit the loop.
656  break;
657  }
658 
659  requestContext = RequestGetContext(request);
660  requestContext->OriginalRequest = OriginalRequest;
661  }
662 
663  // 4.2 Format Srb and Irp
664  {
666  Srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
667  Srb->DataTransferLength = BufferLength;
668  Srb->SrbFlags = deviceExtension->SrbFlags;
669 
670  // Disable synchronous transfer for these requests.
673 
674  if (BufferAddress != NULL)
675  {
676  if (WriteToDevice)
677  {
678  SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DATA_OUT);
679  ioctlCode = IOCTL_SCSI_EXECUTE_OUT;
680  }
681  else
682  {
683  SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DATA_IN);
684  ioctlCode = IOCTL_SCSI_EXECUTE_IN;
685  }
686  }
687  else
688  {
689  ioctlCode = IOCTL_SCSI_EXECUTE_NONE;
690  }
691 
692 
693  // Zero out status.
694  Srb->ScsiStatus = 0;
695  Srb->SrbStatus = 0;
696  Srb->NextSrb = NULL;
697 
698  // irp related fields
699  irp->MdlAddress = mdlAddress;
700 
701  nextStack = IoGetNextIrpStackLocation(irp);
702 
703  nextStack->MajorFunction = IRP_MJ_SCSI;
704  nextStack->Parameters.DeviceIoControl.IoControlCode = ioctlCode;
705  nextStack->Parameters.Scsi.Srb = Srb;
706  }
707 
708  // 4.3 send Request to lower driver.
709  status = DeviceSendRequestSynchronously(Device, request, TRUE);
710 
711  if (status != STATUS_CANCELLED)
712  {
713  NT_ASSERT(SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_PENDING);
715  NT_ASSERT(!(Srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN));
716 
717  // 4.4 error process.
718  if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS)
719  {
720  LONGLONG retryIntervalIn100ns = 0;
721 
722  // Update status and determine if request should be retried.
723  retry = RequestSenseInfoInterpret(deviceExtension,
724  request,
725  Srb,
726  retryCount,
727  &status,
728  &retryIntervalIn100ns);
729 
730  if (retry)
731  {
733  t.QuadPart = -retryIntervalIn100ns;
734  retryCount++;
736  }
737  }
738  else
739  {
740  // Request succeeded.
743  retry = FALSE;
744  }
745  }
746  } while(retry);
747 
748  if ((zpoddInfo != NULL) &&
749  (zpoddInfo->MonitorStartStopUnit != FALSE) &&
750  (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS))
751  {
752  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER,
753  "DeviceSendSrbSynchronously: soft eject detected, device marked as active\n"));
754 
755  DeviceMarkActive(deviceExtension, TRUE, FALSE);
756  }
757 
758  // 5. Release all allocated resources.
759 
760  // required even though we allocated our own, since the port driver may
761  // have allocated one also
762  if (PORT_ALLOCATED_SENSE(deviceExtension, Srb))
763  {
764  FREE_PORT_ALLOCATED_SENSE_BUFFER(deviceExtension, Srb);
765  }
766 
767 Exit:
768 
769  if (senseInfoBuffer != NULL)
770  {
772  }
773 
774  Srb->SenseInfoBuffer = NULL;
775  Srb->SenseInfoBufferLength = 0;
776 
777  if (mdlAddress)
778  {
779  if (memoryLocked)
780  {
781  MmUnlockPages(mdlAddress);
782  memoryLocked = FALSE;
783  }
784 
785  IoFreeMdl(mdlAddress);
786  irp->MdlAddress = NULL;
787  }
788 
789  if (request)
790  {
791  WdfObjectDelete(request);
792  }
793 
794  return status;
795 }
796 
797 
798 VOID
800  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
801  _In_ const GUID* Guid,
803  _In_opt_ PVOID ExtraData
804  )
805 /*++
806 Routine Description:
807 
808  send notification to other components
809 
810 Arguments:
811 
812  DeviceExtension - device context.
813 
814  Guid - GUID for the notification
815 
816  ExtraDataSize - data size along with notification
817 
818  ExtraData - data buffer send with notification
819 
820 Return Value:
821  None
822 
823 --*/
824 {
826  ULONG requiredSize;
828 
829  status = RtlULongAdd((sizeof(TARGET_DEVICE_CUSTOM_NOTIFICATION) - sizeof(UCHAR)),
831  &requiredSize);
832 
833  if (!(NT_SUCCESS(status)) || (requiredSize > 0x0000ffff))
834  {
835  // MAX_USHORT, max total size for these events!
836  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN,
837  "Error sending event: size too large! (%x)\n",
838  requiredSize));
839  return;
840  }
841 
842  notification = ExAllocatePoolWithTag(NonPagedPoolNx,
843  requiredSize,
845 
846  // if none allocated, exit
847  if (notification == NULL)
848  {
849  return;
850  }
851 
852  // Prepare and send the request!
853  RtlZeroMemory(notification, requiredSize);
854  notification->Version = 1;
855  notification->Size = (USHORT)(requiredSize);
856  notification->FileObject = NULL;
857  notification->NameBufferOffset = -1;
858  notification->Event = *Guid;
859 
860  if (ExtraData != NULL)
861  {
862  RtlCopyMemory(notification->CustomDataBuffer, ExtraData, ExtraDataSize);
863  }
864 
865  IoReportTargetDeviceChangeAsynchronous(DeviceExtension->LowerPdo,
866  notification,
867  NULL,
868  NULL);
869 
871 
872  return;
873 }
874 
875 
876 VOID
878  _In_ WDFDEVICE Device
879  )
880 /*++
881 
882 Routine Description:
883 
884  Send command to SCSI unit to start or power up.
885  Because this command is issued asynchronounsly, that is, without
886  waiting on it to complete, the IMMEDIATE flag is not set. This
887  means that the CDB will not return until the drive has powered up.
888  This should keep subsequent requests from being submitted to the
889  device before it has completely spun up.
890 
891  This routine is called from the InterpretSense routine, when a
892  request sense returns data indicating that a drive must be
893  powered up.
894 
895  This routine may also be called from a class driver's error handler,
896  or anytime a non-critical start device should be sent to the device.
897 
898 Arguments:
899 
900  Device - The device object.
901 
902 Return Value:
903 
904  None.
905 
906 --*/
907 {
909  PCDROM_DEVICE_EXTENSION deviceExtension = NULL;
910  WDF_OBJECT_ATTRIBUTES attributes;
911  WDFREQUEST startUnitRequest = NULL;
912  WDFMEMORY inputMemory = NULL;
913 
916  PCDB cdb = NULL;
917 
918  deviceExtension = DeviceGetExtension(Device);
919 
920  if (NT_SUCCESS(status))
921  {
922  // Allocate Srb from nonpaged pool.
923  context = ExAllocatePoolWithTag(NonPagedPoolNx,
924  sizeof(COMPLETION_CONTEXT),
926 
927  if (context == NULL)
928  {
929  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
930  "DeviceSendStartUnit: Failed to allocate completion context\n"));
931 
933  }
934  }
935 
936  if (NT_SUCCESS(status))
937  {
938  // Save the device object in the context for use by the completion
939  // routine.
940  context->Device = Device;
941  srb = &context->Srb;
942 
943  // Zero out srb.
944  RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
945 
946  // setup SRB structure.
947  srb->Length = sizeof(SCSI_REQUEST_BLOCK);
950 
953 
954  // setup CDB
955  srb->CdbLength = 6;
956  cdb = (PCDB)srb->Cdb;
957 
958  cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
959  cdb->START_STOP.Start = 1;
960  cdb->START_STOP.Immediate = 0;
961  cdb->START_STOP.LogicalUnitNumber = srb->Lun;
962 
963  //Create Request for sending down to port driver
966  attributes.ParentObject = deviceExtension->IoTarget;
967 
968  status = WdfRequestCreate(&attributes,
969  deviceExtension->IoTarget,
970  &startUnitRequest);
971  }
972 
973  if (NT_SUCCESS(status))
974  {
975  srb->OriginalRequest = WdfRequestWdmGetIrp(startUnitRequest);
976  NT_ASSERT(srb->OriginalRequest != NULL);
977 
978  //Prepare the request
979  WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
980  attributes.ParentObject = startUnitRequest;
981 
982  status = WdfMemoryCreatePreallocated(&attributes,
983  (PVOID)srb,
984  sizeof(SCSI_REQUEST_BLOCK),
985  &inputMemory);
986  }
987 
988  if (NT_SUCCESS(status))
989  {
990  status = WdfIoTargetFormatRequestForInternalIoctlOthers(deviceExtension->IoTarget,
991  startUnitRequest,
993  inputMemory,
994  NULL,
995  NULL,
996  NULL,
997  NULL,
998  NULL);
999  }
1000 
1001  if (NT_SUCCESS(status))
1002  {
1003  // Set a CompletionRoutine callback function.
1004  WdfRequestSetCompletionRoutine(startUnitRequest,
1006  context);
1007 
1008  status = RequestSend(deviceExtension,
1009  startUnitRequest,
1010  deviceExtension->IoTarget,
1011  0,
1012  NULL);
1013  }
1014 
1015  // release resources when failed.
1016  if (!NT_SUCCESS(status))
1017  {
1018  FREE_POOL(context);
1019  if (startUnitRequest != NULL)
1020  {
1021  WdfObjectDelete(startUnitRequest);
1022  }
1023  }
1024 
1025  return;
1026 } // end StartUnit()
1027 
1028 
1029 VOID
1031  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
1034  )
1035 /*++
1036 
1037 Routine Description:
1038 
1039  Send an IOCTL asynchronously
1040 
1041 Arguments:
1042 
1043  DeviceExtension - device context.
1044  IoControlCode - IOCTL code.
1045  TargetDeviceObject - target device object.
1046 
1047 Return Value:
1048 
1049  None.
1050 
1051 --*/
1052 {
1053  PIRP irp = NULL;
1054  PIO_STACK_LOCATION nextIrpStack = NULL;
1055 
1056  irp = IoAllocateIrp(DeviceExtension->DeviceObject->StackSize, FALSE);
1057 
1058  if (irp != NULL)
1059  {
1060  nextIrpStack = IoGetNextIrpStackLocation(irp);
1061 
1062  nextIrpStack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
1063 
1064  nextIrpStack->Parameters.DeviceIoControl.OutputBufferLength = 0;
1065  nextIrpStack->Parameters.DeviceIoControl.InputBufferLength = 0;
1066  nextIrpStack->Parameters.DeviceIoControl.IoControlCode = IoControlCode;
1067  nextIrpStack->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
1068 
1071  DeviceExtension,
1072  TRUE,
1073  TRUE,
1074  TRUE);
1075 
1077  }
1078 }
1079 
1080 NTSTATUS
1081 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
1084  _In_ PIRP Irp,
1085  _In_reads_opt_(_Inexpressible_("varies")) PVOID Context
1086  )
1087 /*++
1088 
1089 Routine Description:
1090 
1091  Free the Irp.
1092 
1093 Arguments:
1094 
1095  DeviceObject - device that the completion routine fires on.
1096 
1097  Irp - The irp to be completed.
1098 
1099  Context - IRP context
1100 
1101 Return Value:
1102  NTSTATUS
1103 
1104 --*/
1105 {
1108 
1109  IoFreeIrp(Irp);
1110 
1112 }
1113 
1114 VOID
1115 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
1117  _In_ WDFREQUEST Request,
1118  _In_ WDFIOTARGET Target,
1121  )
1122 /*++
1123 
1124 Routine Description:
1125 
1126  This routine is called when an asynchronous I/O request
1127  which was issused by the class driver completes. Examples of such requests
1128  are release queue or START UNIT. This routine releases the queue if
1129  necessary. It then frees the context and the IRP.
1130 
1131 Arguments:
1132 
1133  DeviceObject - The device object for the logical unit; however since this
1134  is the top stack location the value is NULL.
1135 
1136  Irp - Supplies a pointer to the Irp to be processed.
1137 
1138  Context - Supplies the context to be used to process this request.
1139 
1140 Return Value:
1141 
1142  None.
1143 
1144 --*/
1145 {
1147  PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(context->Device);
1148 
1151 
1152  // If this is an execute srb, then check the return status and make sure.
1153  // the queue is not frozen.
1154  if (context->Srb.Function == SRB_FUNCTION_EXECUTE_SCSI)
1155  {
1156  // Check for a frozen queue.
1157  if (context->Srb.SrbStatus & SRB_STATUS_QUEUE_FROZEN)
1158  {
1159  // Unfreeze the queue getting the device object from the context.
1160  DeviceReleaseQueue(context->Device);
1161  }
1162  }
1163 
1164  // free port-allocated sense buffer if we can detect
1165  //
1166  if (PORT_ALLOCATED_SENSE(deviceExtension, &context->Srb))
1167  {
1168  FREE_PORT_ALLOCATED_SENSE_BUFFER(deviceExtension, &context->Srb);
1169  }
1170 
1171  FREE_POOL(context);
1172 
1173  WdfObjectDelete(Request);
1174 
1175 } // end DeviceAsynchronousCompletion()
1176 
1177 
1178 VOID
1180  _In_ WDFDEVICE Device
1181  )
1182 /*++
1183 
1184 Routine Description:
1185 
1186  This routine issues an internal device control command
1187  to the port driver to release a frozen queue. The call
1188  is issued asynchronously as DeviceReleaseQueue will be invoked
1189  from the IO completion DPC (and will have no context to
1190  wait for a synchronous call to complete).
1191 
1192  This routine must be called with the remove lock held.
1193 
1194 Arguments:
1195 
1196  Device - The functional device object for the device with the frozen queue.
1197 
1198 Return Value:
1199 
1200  None.
1201 
1202 --*/
1203 {
1204  PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device);
1205  PSCSI_REQUEST_BLOCK srb = NULL;
1206  KIRQL currentIrql;
1207 
1208  // we raise irql seperately so we're not swapped out or suspended
1209  // while holding the release queue irp in this routine. this lets
1210  // us release the spin lock before lowering irql.
1211  KeRaiseIrql(DISPATCH_LEVEL, &currentIrql);
1212 
1213  WdfSpinLockAcquire(deviceExtension->ReleaseQueueSpinLock);
1214 
1215  if (deviceExtension->ReleaseQueueInProgress)
1216  {
1217  // Someone is already doing this work - just set the flag to indicate that
1218  // we need to release the queue again.
1219  deviceExtension->ReleaseQueueNeeded = TRUE;
1220  WdfSpinLockRelease(deviceExtension->ReleaseQueueSpinLock);
1221  KeLowerIrql(currentIrql);
1222 
1223  return;
1224  }
1225 
1226  // Mark that there is a release queue in progress and drop the spinlock.
1227  deviceExtension->ReleaseQueueInProgress = TRUE;
1228 
1229  WdfSpinLockRelease(deviceExtension->ReleaseQueueSpinLock);
1230 
1231  srb = &(deviceExtension->ReleaseQueueSrb);
1232 
1233  // Optical media are removable, so we just flush the queue. This will also release it.
1235 
1236  srb->OriginalRequest = WdfRequestWdmGetIrp(deviceExtension->ReleaseQueueRequest);
1237 
1238  // Set a CompletionRoutine callback function.
1239  WdfRequestSetCompletionRoutine(deviceExtension->ReleaseQueueRequest,
1241  Device);
1242  // Send the request. If an error occurs, complete the request.
1243  RequestSend(deviceExtension,
1244  deviceExtension->ReleaseQueueRequest,
1245  deviceExtension->IoTarget,
1247  NULL);
1248 
1249  KeLowerIrql(currentIrql);
1250 
1251  return;
1252 
1253 } // end DeviceReleaseQueue()
1254 
1255 VOID
1256 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
1258  _In_ WDFREQUEST Request,
1259  _In_ WDFIOTARGET Target,
1262  )
1263 /*++
1264 
1265 Routine Description:
1266 
1267  This routine is called when an asynchronous release queue request which
1268  was issused in DeviceReleaseQueue completes. This routine prepares for
1269  the next release queue request and resends it if necessary.
1270 
1271 Arguments:
1272 
1273  Request - The completed request.
1274 
1275  Target - IoTarget object
1276 
1277  Params - Completion parameters
1278 
1279  Context - WDFDEVICE object handle.
1280 
1281 Return Value:
1282 
1283  None.
1284 
1285 --*/
1286 {
1287  NTSTATUS status;
1288  WDFDEVICE device = Context;
1289  PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(device);
1290 
1291  BOOLEAN releaseQueueNeeded = FALSE;
1293 
1296 
1299  STATUS_SUCCESS);
1300 
1301  // Grab the spinlock and clear the release queue in progress flag so others
1302  // can run. Save (and clear) the state of the release queue needed flag
1303  // so that we can issue a new release queue outside the spinlock.
1304  WdfSpinLockAcquire(deviceExtension->ReleaseQueueSpinLock);
1305 
1306  releaseQueueNeeded = deviceExtension->ReleaseQueueNeeded;
1307 
1308  deviceExtension->ReleaseQueueNeeded = FALSE;
1309  deviceExtension->ReleaseQueueInProgress = FALSE;
1310 
1311  // Reuse the ReleaseQueueRequest for the next time.
1312  status = WdfRequestReuse(Request,&params);
1313 
1314  if (NT_SUCCESS(status))
1315  {
1316  // Preformat the ReleaseQueueRequest for the next time.
1317  // This should always succeed because it was already preformatted once during device initialization
1318  status = WdfIoTargetFormatRequestForInternalIoctlOthers(deviceExtension->IoTarget,
1319  Request,
1321  deviceExtension->ReleaseQueueInputMemory,
1322  NULL,
1323  NULL,
1324  NULL,
1325  NULL,
1326  NULL);
1327  }
1328 
1329  if (!NT_SUCCESS(status))
1330  {
1331  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
1332  "DeviceReleaseQueueCompletion: WdfIoTargetFormatRequestForInternalIoctlOthers failed, %!STATUS!\n",
1333  status));
1334  }
1335 
1337 
1338  WdfSpinLockRelease(deviceExtension->ReleaseQueueSpinLock);
1339 
1340  // If we need a release queue then issue one now. Another processor may
1341  // have already started one in which case we'll try to issue this one after
1342  // it is done - but we should never recurse more than one deep.
1343  if (releaseQueueNeeded)
1344  {
1346  }
1347 
1348  return;
1349 
1350 } // DeviceReleaseQueueCompletion()
1351 
1352 
1353 //
1354 // In order to provide better performance without the need to reboot,
1355 // we need to implement a self-adjusting method to set and clear the
1356 // srb flags based upon current performance.
1357 //
1358 // whenever there is an error, immediately grab the spin lock. the
1359 // MP perf hit here is acceptable, since we're in an error path. this
1360 // is also neccessary because we are guaranteed to be modifying the
1361 // SRB flags here, setting SuccessfulIO to zero, and incrementing the
1362 // actual error count (which is always done within this spinlock).
1363 //
1364 // whenever there is no error, increment a counter. if there have been
1365 // errors on the device, and we've enabled dynamic perf, *and* we've
1366 // just crossed the perf threshhold, then grab the spin lock and
1367 // double check that the threshhold has, indeed been hit(*). then
1368 // decrement the error count, and if it's dropped sufficiently, undo
1369 // some of the safety changes made in the SRB flags due to the errors.
1370 //
1371 // * this works in all cases. even if lots of ios occur after the
1372 // previous guy went in and cleared the successfulio counter, that
1373 // just means that we've hit the threshhold again, and so it's proper
1374 // to run the inner loop again.
1375 //
1376 
1377 VOID
1379  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
1380  )
1381 {
1382  PCDROM_PRIVATE_FDO_DATA fdoData = DeviceExtension->PrivateFdoData;
1383  KIRQL oldIrql;
1384  ULONG errors;
1385 
1386  KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql);
1387 
1388  fdoData->Perf.SuccessfulIO = 0; // implicit interlock
1389  errors = InterlockedIncrement((PLONG)&DeviceExtension->ErrorCount);
1390 
1391  if (errors >= CLASS_ERROR_LEVEL_1)
1392  {
1393  // If the error count has exceeded the error limit, then disable
1394  // any tagged queuing, multiple requests per lu queueing
1395  // and sychronous data transfers.
1396  //
1397  // Clearing the no queue freeze flag prevents the port driver
1398  // from sending multiple requests per logical unit.
1399  CLEAR_FLAG(DeviceExtension->SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE);
1400  CLEAR_FLAG(DeviceExtension->SrbFlags, SRB_FLAGS_QUEUE_ACTION_ENABLE);
1401 
1402  SET_FLAG(DeviceExtension->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
1403 
1404  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
1405  "PerfIncrementErrorCount: Too many errors; disabling tagged queuing and "
1406  "synchronous data tranfers.\n"));
1407  }
1408 
1409  if (errors >= CLASS_ERROR_LEVEL_2)
1410  {
1411  // If a second threshold is reached, disable disconnects.
1412  SET_FLAG(DeviceExtension->SrbFlags, SRB_FLAGS_DISABLE_DISCONNECT);
1413  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
1414  "PerfIncrementErrorCount: Too many errors; disabling disconnects.\n"));
1415  }
1416 
1417  KeReleaseSpinLock(&fdoData->SpinLock, oldIrql);
1418  return;
1419 }
1420 
1421 
1423 PVOID
1424 DeviceFindFeaturePage(
1426  _In_ ULONG const Length,
1428  )
1429 /*++
1430 Routine Description:
1431 
1432  find the specific feature page in the buffer
1433 
1434 Arguments:
1435 
1436  FeatureBuffer - buffer contains the device feature set.
1437 
1438  Length - buffer length
1439 
1440  Feature - the feature number looking for.
1441 
1442 Return Value:
1443 
1444  PVOID - pointer to the starting location of the specific feature in buffer.
1445 
1446 --*/
1447 {
1448  PUCHAR buffer;
1449  PUCHAR limit;
1450  ULONG validLength;
1451 
1452  PAGED_CODE();
1453 
1454  if (Length < sizeof(GET_CONFIGURATION_HEADER) + sizeof(FEATURE_HEADER))
1455  {
1456  return NULL;
1457  }
1458 
1459  // Calculate the length of valid data available in the
1460  // capabilities buffer from the DataLength field
1461  REVERSE_BYTES(&validLength, FeatureBuffer->DataLength);
1462 
1464 
1465  // set limit to point to first illegal address
1466  limit = (PUCHAR)FeatureBuffer;
1467  limit += min(Length, validLength);
1468 
1469  // set buffer to point to first page
1470  buffer = FeatureBuffer->Data;
1471 
1472  // loop through each page until we find the requested one, or
1473  // until it's not safe to access the entire feature header
1474  // (if equal, have exactly enough for the feature header)
1475  while (buffer + sizeof(FEATURE_HEADER) <= limit)
1476  {
1478  FEATURE_NUMBER thisFeature;
1479 
1480  thisFeature = (header->FeatureCode[0] << 8) |
1481  (header->FeatureCode[1]);
1482 
1483  if (thisFeature == Feature)
1484  {
1485  PUCHAR temp;
1486 
1487  // if don't have enough memory to safely access all the feature
1488  // information, return NULL
1489  temp = buffer;
1490  temp += sizeof(FEATURE_HEADER);
1491  temp += header->AdditionalLength;
1492 
1493  if (temp > limit)
1494  {
1495  // this means the transfer was cut-off, an insufficiently
1496  // small buffer was given, or other arbitrary error. since
1497  // it's not safe to view the amount of data (even though
1498  // the header is safe) in this feature, pretend it wasn't
1499  // transferred at all...
1500  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL,
1501  "Feature %x exists, but not safe to access all its data. returning NULL\n",
1502  Feature));
1503  return NULL;
1504  }
1505  else
1506  {
1507  return buffer;
1508  }
1509  }
1510 
1511  if ((header->AdditionalLength % 4) &&
1512  !(Feature >= 0xff00 && Feature <= 0xffff))
1513  {
1514  return NULL;
1515  }
1516 
1517  buffer += sizeof(FEATURE_HEADER);
1518  buffer += header->AdditionalLength;
1519  }
1520 
1521  return NULL;
1522 }
1523 
1524 
1526 VOID
1527 DevicePrintAllFeaturePages(
1529  _In_ ULONG const Usable
1530  )
1531 /*++
1532 Routine Description:
1533 
1534  print out all feature pages in the buffer
1535 
1536 Arguments:
1537 
1538  Buffer - buffer contains the device feature set.
1539 
1540  Usable -
1541 
1542 Return Value:
1543 
1544  none
1545 
1546 --*/
1547 {
1548 #if DBG
1550 
1551  PAGED_CODE();
1552 
1554  // items expected to ALWAYS be current if they exist
1556 
1557  header = DeviceFindFeaturePage(Buffer, Usable, FeatureProfileList);
1558  if (header != NULL) {
1559  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1560  "CdromGetConfiguration: CurrentProfile %x "
1561  "with %x bytes of data at %p\n",
1562  Buffer->CurrentProfile[0] << 8 |
1563  Buffer->CurrentProfile[1],
1564  Usable, Buffer));
1565  }
1566 
1567  header = DeviceFindFeaturePage(Buffer, Usable, FeatureCore);
1568  if (header) {
1569  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1570  "CdromGetConfiguration: %s %s\n",
1571  (header->Current ?
1572  "Currently supports" : "Is able to support"),
1573  "CORE Features"
1574  ));
1575  }
1576 
1577  header = DeviceFindFeaturePage(Buffer, Usable, FeatureMorphing);
1578  if (header) {
1579  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1580  "CdromGetConfiguration: %s %s\n",
1581  (header->Current ?
1582  "Currently supports" : "Is able to support"),
1583  "Morphing"
1584  ));
1585  }
1586 
1587  header = DeviceFindFeaturePage(Buffer, Usable, FeatureRemovableMedium);
1588  if (header) {
1589  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1590  "CdromGetConfiguration: %s %s\n",
1591  (header->Current ?
1592  "Currently supports" : "Is able to support"),
1593  "Removable Medium"
1594  ));
1595  }
1596 
1597  header = DeviceFindFeaturePage(Buffer, Usable, FeaturePowerManagement);
1598  if (header) {
1599  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1600  "CdromGetConfiguration: %s %s\n",
1601  (header->Current ?
1602  "Currently supports" : "Is able to support"),
1603  "Power Management"
1604  ));
1605  }
1606 
1607  header = DeviceFindFeaturePage(Buffer, Usable, FeatureEmbeddedChanger);
1608  if (header) {
1609  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1610  "CdromGetConfiguration: %s %s\n",
1611  (header->Current ?
1612  "Currently supports" : "Is able to support"),
1613  "Embedded Changer"
1614  ));
1615  }
1616 
1617  header = DeviceFindFeaturePage(Buffer, Usable, FeatureMicrocodeUpgrade);
1618  if (header) {
1619  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1620  "CdromGetConfiguration: %s %s\n",
1621  (header->Current ?
1622  "Currently supports" : "Is able to support"),
1623  "Microcode Update"
1624  ));
1625  }
1626 
1627  header = DeviceFindFeaturePage(Buffer, Usable, FeatureTimeout);
1628  if (header) {
1629  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1630  "CdromGetConfiguration: %s %s\n",
1631  (header->Current ?
1632  "Currently supports" : "Is able to support"),
1633  "Timeouts"
1634  ));
1635  }
1636 
1637  header = DeviceFindFeaturePage(Buffer, Usable, FeatureLogicalUnitSerialNumber);
1638  if (header) {
1639  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1640  "CdromGetConfiguration: %s %s\n",
1641  (header->Current ?
1642  "Currently supports" : "Is able to support"),
1643  "LUN Serial Number"
1644  ));
1645  }
1646 
1647  header = DeviceFindFeaturePage(Buffer, Usable, FeatureFirmwareDate);
1648  if (header) {
1649 
1650  ULONG featureSize = header->AdditionalLength;
1651  featureSize += RTL_SIZEOF_THROUGH_FIELD(FEATURE_HEADER, AdditionalLength);
1652 
1653  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1654  "CdromGetConfiguration: %s %s\n",
1655  (header->Current ?
1656  "Currently supports" : "Is able to support"),
1657  "Firmware Date"
1658  ));
1659 
1660  if (featureSize >= RTL_SIZEOF_THROUGH_FIELD(FEATURE_DATA_FIRMWARE_DATE, Minute))
1661  {
1663  // show date as "YYYY/MM/DD hh:mm", which is 18 chars (17+NULL)
1664  UCHAR dateString[18] = { 0 };
1665  dateString[ 0] = date->Year[0];
1666  dateString[ 1] = date->Year[1];
1667  dateString[ 2] = date->Year[2];
1668  dateString[ 3] = date->Year[3];
1669  dateString[ 4] = '/';
1670  dateString[ 5] = date->Month[0];
1671  dateString[ 6] = date->Month[1];
1672  dateString[ 7] = '/';
1673  dateString[ 8] = date->Day[0];
1674  dateString[ 9] = date->Day[1];
1675  dateString[10] = ' ';
1676  dateString[11] = ' ';
1677  dateString[12] = date->Hour[0];
1678  dateString[13] = date->Hour[1];
1679  dateString[14] = ':';
1680  dateString[15] = date->Minute[0];
1681  dateString[16] = date->Minute[1];
1682  dateString[17] = 0;
1683  // SECONDS IS NOT AVAILABLE ON EARLY IMPLEMENTATIONS -- ignore it
1684  //dateString[17] = ':';
1685  //dateString[18] = date->Seconds[0];
1686  //dateString[19] = date->Seconds[1];
1687  //dateString[20] = 0;
1688  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1689  "CdromGetConfiguration: Firmware Date/Time %s (UTC)\n",
1690  (PCSTR)dateString
1691  ));
1692  }
1693  }
1694 
1696 // items expected not to always be current
1698 
1699 
1700  header = DeviceFindFeaturePage(Buffer, Usable, FeatureWriteProtect);
1701  if (header) {
1702  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL,
1703  "CdromGetConfiguration: %s %s\n",
1704  (header->Current ?
1705  "Currently supports" : "Is able to support"),
1706  "Software Write Protect"
1707  ));
1708  }
1709 
1710  header = DeviceFindFeaturePage(Buffer, Usable, FeatureRandomReadable);
1711  if (header) {
1712  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1713  "CdromGetConfiguration: %s %s\n",
1714  (header->Current ?
1715  "Currently supports" : "Is able to support"),
1716  "Random Reads"
1717  ));
1718  }
1719 
1720  header = DeviceFindFeaturePage(Buffer, Usable, FeatureMultiRead);
1721  if (header) {
1722  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1723  "CdromGetConfiguration: %s %s\n",
1724  (header->Current ?
1725  "Currently supports" : "Is able to support"),
1726  "Multi-Read"
1727  ));
1728  }
1729 
1730  header = DeviceFindFeaturePage(Buffer, Usable, FeatureCdRead);
1731  if (header) {
1732  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1733  "CdromGetConfiguration: %s %s\n",
1734  (header->Current ?
1735  "Currently supports" : "Is able to support"),
1736  "reading from CD-ROM/R/RW"
1737  ));
1738  }
1739 
1740  header = DeviceFindFeaturePage(Buffer, Usable, FeatureDvdRead);
1741  if (header) {
1742  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1743  "CdromGetConfiguration: %s %s\n",
1744  (header->Current ?
1745  "Currently supports" : "Is able to support"),
1746  "DVD Structure Reads"
1747  ));
1748  }
1749 
1750  header = DeviceFindFeaturePage(Buffer, Usable, FeatureRandomWritable);
1751  if (header) {
1752  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1753  "CdromGetConfiguration: %s %s\n",
1754  (header->Current ?
1755  "Currently supports" : "Is able to support"),
1756  "Random Writes"
1757  ));
1758  }
1759 
1760  header = DeviceFindFeaturePage(Buffer, Usable, FeatureIncrementalStreamingWritable);
1761  if (header) {
1762  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1763  "CdromGetConfiguration: %s %s\n",
1764  (header->Current ?
1765  "Currently supports" : "Is able to support"),
1766  "Incremental Streaming Writing"
1767  ));
1768  }
1769 
1770  header = DeviceFindFeaturePage(Buffer, Usable, FeatureSectorErasable);
1771  if (header) {
1772  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1773  "CdromGetConfiguration: %s %s\n",
1774  (header->Current ?
1775  "Currently supports" : "Is able to support"),
1776  "Sector Erasable Media"
1777  ));
1778  }
1779 
1780  header = DeviceFindFeaturePage(Buffer, Usable, FeatureFormattable);
1781  if (header) {
1782  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1783  "CdromGetConfiguration: %s %s\n",
1784  (header->Current ?
1785  "Currently supports" : "Is able to support"),
1786  "Formatting"
1787  ));
1788  }
1789 
1790  header = DeviceFindFeaturePage(Buffer, Usable, FeatureDefectManagement);
1791  if (header) {
1792  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1793  "CdromGetConfiguration: %s %s\n",
1794  (header->Current ?
1795  "Currently supports" : "Is able to support"),
1796  "defect management"
1797  ));
1798  }
1799 
1800  header = DeviceFindFeaturePage(Buffer, Usable, FeatureWriteOnce);
1801  if (header) {
1802  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1803  "CdromGetConfiguration: %s %s\n",
1804  (header->Current ?
1805  "Currently supports" : "Is able to support"),
1806  "Write Once Media"
1807  ));
1808  }
1809 
1810  header = DeviceFindFeaturePage(Buffer, Usable, FeatureRestrictedOverwrite);
1811  if (header) {
1812  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1813  "CdromGetConfiguration: %s %s\n",
1814  (header->Current ?
1815  "Currently supports" : "Is able to support"),
1816  "Restricted Overwrites"
1817  ));
1818  }
1819 
1820  header = DeviceFindFeaturePage(Buffer, Usable, FeatureCdrwCAVWrite);
1821  if (header) {
1822  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1823  "CdromGetConfiguration: %s %s\n",
1824  (header->Current ?
1825  "Currently supports" : "Is able to support"),
1826  "CD-RW CAV recording"
1827  ));
1828  }
1829 
1830  header = DeviceFindFeaturePage(Buffer, Usable, FeatureMrw);
1831  if (header) {
1832  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1833  "CdromGetConfiguration: %s %s\n",
1834  (header->Current ?
1835  "Currently supports" : "Is able to support"),
1836  "Mount Rainier media"
1837  ));
1838  }
1839 
1840  header = DeviceFindFeaturePage(Buffer, Usable, FeatureEnhancedDefectReporting);
1841  if (header) {
1842  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1843  "CdromGetConfiguration: %s %s\n",
1844  (header->Current ?
1845  "Currently supports" : "Is able to support"),
1846  "Enhanced Defect Reporting"
1847  ));
1848  }
1849 
1850  header = DeviceFindFeaturePage(Buffer, Usable, FeatureDvdPlusRW);
1851  if (header) {
1852  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1853  "CdromGetConfiguration: %s %s\n",
1854  (header->Current ?
1855  "Currently supports" : "Is able to support"),
1856  "DVD+RW media"
1857  ));
1858  }
1859 
1860  header = DeviceFindFeaturePage(Buffer, Usable, FeatureRigidRestrictedOverwrite);
1861  if (header) {
1862  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1863  "CdromGetConfiguration: %s %s\n",
1864  (header->Current ?
1865  "Currently supports" : "Is able to support"),
1866  "Rigid Restricted Overwrite"
1867  ));
1868  }
1869 
1870  header = DeviceFindFeaturePage(Buffer, Usable, FeatureCdTrackAtOnce);
1871  if (header) {
1872  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1873  "CdromGetConfiguration: %s %s\n",
1874  (header->Current ?
1875  "Currently supports" : "Is able to support"),
1876  "CD Recording (Track At Once)"
1877  ));
1878  }
1879 
1880  header = DeviceFindFeaturePage(Buffer, Usable, FeatureCdMastering);
1881  if (header) {
1882  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1883  "CdromGetConfiguration: %s %s\n",
1884  (header->Current ?
1885  "Currently supports" : "Is able to support"),
1886  "CD Recording (Mastering)"
1887  ));
1888  }
1889 
1890  header = DeviceFindFeaturePage(Buffer, Usable, FeatureDvdRecordableWrite);
1891  if (header) {
1892  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1893  "CdromGetConfiguration: %s %s\n",
1894  (header->Current ?
1895  "Currently supports" : "Is able to support"),
1896  "DVD Recording (Mastering)"
1897  ));
1898  }
1899 
1900  header = DeviceFindFeaturePage(Buffer, Usable, FeatureDDCDRead);
1901  if (header) {
1902  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1903  "CdromGetConfiguration: %s %s\n",
1904  (header->Current ?
1905  "Currently supports" : "Is able to support"),
1906  "DD CD Reading"
1907  ));
1908  }
1909 
1910  header = DeviceFindFeaturePage(Buffer, Usable, FeatureDDCDRWrite);
1911  if (header) {
1912  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1913  "CdromGetConfiguration: %s %s\n",
1914  (header->Current ?
1915  "Currently supports" : "Is able to support"),
1916  "DD CD-R Writing"
1917  ));
1918  }
1919 
1920  header = DeviceFindFeaturePage(Buffer, Usable, FeatureDDCDRWWrite);
1921  if (header) {
1922  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1923  "CdromGetConfiguration: %s %s\n",
1924  (header->Current ?
1925  "Currently supports" : "Is able to support"),
1926  "DD CD-RW Writing"
1927  ));
1928  }
1929 
1930  header = DeviceFindFeaturePage(Buffer, Usable, FeatureLayerJumpRecording);
1931  if (header) {
1932  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1933  "CdromGetConfiguration: %s %s\n",
1934  (header->Current ?
1935  "Currently supports" : "Is able to support"),
1936  "Layer Jump Recording"
1937  ));
1938  }
1939 
1940  header = DeviceFindFeaturePage(Buffer, Usable, FeatureHDDVDRead);
1941  if (header) {
1942  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1943  "CdromGetConfiguration: %s %s\n",
1944  (header->Current ?
1945  "Currently supports" : "Is able to support"),
1946  "HD-DVD Reading"
1947  ));
1948  }
1949 
1950  header = DeviceFindFeaturePage(Buffer, Usable, FeatureHDDVDWrite);
1951  if (header) {
1952  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1953  "CdromGetConfiguration: %s %s\n",
1954  (header->Current ?
1955  "Currently supports" : "Is able to support"),
1956  "HD-DVD Writing"
1957  ));
1958  }
1959 
1960 
1961  header = DeviceFindFeaturePage(Buffer, Usable, FeatureSMART);
1962  if (header) {
1963  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1964  "CdromGetConfiguration: %s %s\n",
1965  (header->Current ?
1966  "Currently supports" : "Is able to support"),
1967  "S.M.A.R.T."
1968  ));
1969  }
1970 
1971  header = DeviceFindFeaturePage(Buffer, Usable, FeatureCDAudioAnalogPlay);
1972  if (header) {
1973  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1974  "CdromGetConfiguration: %s %s\n",
1975  (header->Current ?
1976  "Currently supports" : "Is able to support"),
1977  "Analogue CD Audio Operations"
1978  ));
1979  }
1980 
1981  header = DeviceFindFeaturePage(Buffer, Usable, FeatureDvdCSS);
1982  if (header) {
1983  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1984  "CdromGetConfiguration: %s %s\n",
1985  (header->Current ?
1986  "Currently supports" : "Is able to support"),
1987  "DVD CSS"
1988  ));
1989  }
1990 
1991  header = DeviceFindFeaturePage(Buffer, Usable, FeatureRealTimeStreaming);
1992  if (header) {
1993  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1994  "CdromGetConfiguration: %s %s\n",
1995  (header->Current ?
1996  "Currently supports" : "Is able to support"),
1997  "Real-time Streaming Reads"
1998  ));
1999  }
2000 
2001  header = DeviceFindFeaturePage(Buffer, Usable, FeatureDiscControlBlocks);
2002  if (header) {
2003  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
2004  "CdromGetConfiguration: %s %s\n",
2005  (header->Current ?
2006  "Currently supports" : "Is able to support"),
2007  "DVD Disc Control Blocks"
2008  ));
2009  }
2010 
2011  header = DeviceFindFeaturePage(Buffer, Usable, FeatureDvdCPRM);
2012  if (header) {
2013  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
2014  "CdromGetConfiguration: %s %s\n",
2015  (header->Current ?
2016  "Currently supports" : "Is able to support"),
2017  "DVD CPRM"
2018  ));
2019  }
2020 
2021  header = DeviceFindFeaturePage(Buffer, Usable, FeatureAACS);
2022  if (header) {
2023  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
2024  "CdromGetConfiguration: %s %s\n",
2025  (header->Current ?
2026  "Currently supports" : "Is able to support"),
2027  "AACS"
2028  ));
2029  }
2030 
2031 #else
2032  PAGED_CODE();
2033 
2036 
2037 #endif // DBG
2038  return;
2039 }
2040 
2041 
2043 NTSTATUS
2044 MediaReadCapacity(
2045  _In_ WDFDEVICE Device
2046  )
2047 /*++
2048 Routine Description:
2049 
2050  Get media capacity
2051 
2052 Arguments:
2053 
2054  Device - the device that owns the media
2055 
2056 Return Value:
2057 
2058  NTSTATUS
2059 
2060 --*/
2061 {
2062  NTSTATUS status;
2063  SCSI_REQUEST_BLOCK srb;
2064  PCDB cdb = NULL;
2065  READ_CAPACITY_DATA capacityData;
2066 
2067  PAGED_CODE();
2068 
2069  RtlZeroMemory(&srb, sizeof(srb));
2070  RtlZeroMemory(&capacityData, sizeof(capacityData));
2071 
2072  cdb = (PCDB)(&srb.Cdb);
2073 
2074  //Prepare SCSI command fields
2075  srb.CdbLength = 10;
2077  cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
2078 
2079  status = DeviceSendSrbSynchronously(Device,
2080  &srb,
2081  &capacityData,
2082  sizeof(READ_CAPACITY_DATA),
2083  FALSE,
2084  NULL);
2085 
2086  //Remember the result
2087  if (!NT_SUCCESS(status))
2088  {
2089  //Set the BytesPerBlock to zero, this is for safe as if error happens this field should stay zero (no change).
2090  //it will be treated as error case in MediaReadCapacityDataInterpret()
2091  capacityData.BytesPerBlock = 0;
2092  }
2093 
2094  MediaReadCapacityDataInterpret(Device, &capacityData);
2095 
2096  return status;
2097 }
2098 
2099 
2101 VOID
2102 MediaReadCapacityDataInterpret(
2103  _In_ WDFDEVICE Device,
2105  )
2106 /*++
2107 Routine Description:
2108 
2109  Interpret media capacity and set corresponding fields in device context
2110 
2111 Arguments:
2112 
2113  Device - the device that owns the media
2114 
2115  ReadCapacityBuffer - data buffer of capacity
2116 
2117 Return Value:
2118 
2119  none
2120 
2121 --*/
2122 {
2123  PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device);
2124  ULONG lastSector = 0;
2125  ULONG bps = 0;
2126  ULONG lastBit = 0;
2127  ULONG bytesPerBlock = 0;
2128  BOOLEAN errorHappened = FALSE;
2129 
2130  PAGED_CODE();
2131 
2133 
2134  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
2135  "MediaReadCapacityDataInterpret: Entering\n"));
2136 
2137  // Swizzle bytes from Read Capacity and translate into
2138  // the necessary geometry information in the device extension.
2139  bytesPerBlock = ReadCapacityBuffer->BytesPerBlock;
2140 
2141  ((PFOUR_BYTE)&bps)->Byte0 = ((PFOUR_BYTE)&bytesPerBlock)->Byte3;
2142  ((PFOUR_BYTE)&bps)->Byte1 = ((PFOUR_BYTE)&bytesPerBlock)->Byte2;
2143  ((PFOUR_BYTE)&bps)->Byte2 = ((PFOUR_BYTE)&bytesPerBlock)->Byte1;
2144  ((PFOUR_BYTE)&bps)->Byte3 = ((PFOUR_BYTE)&bytesPerBlock)->Byte0;
2145 
2146  // Insure that bps is a power of 2.
2147  // This corrects a problem with the HP 4020i CDR where it
2148  // returns an incorrect number for bytes per sector.
2149  if (!bps)
2150  {
2151  // Set disk geometry to default values (per ISO 9660).
2152  bps = 2048;
2153  errorHappened = TRUE;
2154  }
2155  else
2156  {
2157  lastBit = (ULONG)(-1);
2158  while (bps)
2159  {
2160  lastBit++;
2161  bps = (bps >> 1);
2162  }
2163  bps = (1 << lastBit);
2164  }
2165 
2166  deviceExtension->DiskGeometry.BytesPerSector = bps;
2167 
2168  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
2169  "MediaReadCapacityDataInterpret: Calculated bps %#x\n",
2170  deviceExtension->DiskGeometry.BytesPerSector));
2171 
2172  // Copy last sector in reverse byte order.
2173  bytesPerBlock = ReadCapacityBuffer->LogicalBlockAddress;
2174 
2175  ((PFOUR_BYTE)&lastSector)->Byte0 = ((PFOUR_BYTE)&bytesPerBlock)->Byte3;
2176  ((PFOUR_BYTE)&lastSector)->Byte1 = ((PFOUR_BYTE)&bytesPerBlock)->Byte2;
2177  ((PFOUR_BYTE)&lastSector)->Byte2 = ((PFOUR_BYTE)&bytesPerBlock)->Byte1;
2178  ((PFOUR_BYTE)&lastSector)->Byte3 = ((PFOUR_BYTE)&bytesPerBlock)->Byte0;
2179 
2180  // Calculate sector to byte shift.
2181  WHICH_BIT(bps, deviceExtension->SectorShift);
2182 
2183  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL,
2184  "MediaReadCapacityDataInterpret: Sector size is %d\n",
2185  deviceExtension->DiskGeometry.BytesPerSector));
2186 
2187  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
2188  "MediaReadCapacityDataInterpret: Number of Sectors is %d\n",
2189  lastSector + 1));
2190 
2191  // Calculate media capacity in bytes.
2192  if (errorHappened)
2193  {
2194  // Set disk geometry to default values (per ISO 9660).
2195  deviceExtension->PartitionLength.QuadPart = (LONGLONG)(0x7fffffff);
2196  }
2197  else
2198  {
2199  deviceExtension->PartitionLength.QuadPart = (LONGLONG)(lastSector + 1);
2200  deviceExtension->PartitionLength.QuadPart =
2201  (deviceExtension->PartitionLength.QuadPart << deviceExtension->SectorShift);
2202  }
2203 
2204  // we've defaulted to 32/64 forever. don't want to change this now...
2205  deviceExtension->DiskGeometry.TracksPerCylinder = 0x40;
2206  deviceExtension->DiskGeometry.SectorsPerTrack = 0x20;
2207 
2208  // Calculate number of cylinders.
2209  deviceExtension->DiskGeometry.Cylinders.QuadPart = (LONGLONG)((lastSector + 1) / (32 * 64));
2210 
2211  deviceExtension->DiskGeometry.MediaType = RemovableMedia;
2212 
2213  return;
2214 }
2215 
2216 
2218 VOID
2219 DevicePickDvdRegion(
2220  _In_ WDFDEVICE Device
2221  )
2222 /*++
2223 
2224 Routine Description:
2225 
2226  pick a default dvd region
2227 
2228 Arguments:
2229 
2230  Device - Device Object
2231 
2232 Return Value:
2233 
2234  none
2235 
2236 --*/
2237 {
2238  NTSTATUS status;
2239  PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device);
2240 
2241  // these five pointers all point to dvdReadStructure or part of
2242  // its data, so don't deallocate them more than once!
2243  PDVD_READ_STRUCTURE dvdReadStructure;
2244  PDVD_COPY_PROTECT_KEY copyProtectKey;
2245  PDVD_COPYRIGHT_DESCRIPTOR dvdCopyRight;
2246  PDVD_RPC_KEY rpcKey;
2247  PDVD_SET_RPC_KEY dvdRpcKey;
2248 
2249  size_t bytesReturned = 0;
2250  ULONG bufferLen = 0;
2251  UCHAR mediaRegion = 0;
2252  ULONG pickDvdRegion = 0;
2253  ULONG defaultDvdRegion = 0;
2254  ULONG dvdRegion = 0;
2255  WDFKEY registryKey = NULL;
2256 
2258 
2259  PAGED_CODE();
2260 
2261  if ((pickDvdRegion = InterlockedExchange((PLONG)&deviceExtension->DeviceAdditionalData.PickDvdRegion, 0)) == 0)
2262  {
2263  // it was non-zero, so either another thread will do this, or
2264  // we no longer need to pick a region
2265  return;
2266  }
2267 
2268  bufferLen = max(
2269  max(sizeof(DVD_DESCRIPTOR_HEADER) +
2270  sizeof(DVD_COPYRIGHT_DESCRIPTOR),
2271  sizeof(DVD_READ_STRUCTURE)
2272  ),
2275  )
2276  );
2277 
2278  dvdReadStructure = (PDVD_READ_STRUCTURE)
2280 
2281  if (dvdReadStructure == NULL)
2282  {
2283  InterlockedExchange((PLONG)&deviceExtension->DeviceAdditionalData.PickDvdRegion, pickDvdRegion);
2284  return;
2285  }
2286 
2287  copyProtectKey = (PDVD_COPY_PROTECT_KEY)dvdReadStructure;
2288 
2289  dvdCopyRight = (PDVD_COPYRIGHT_DESCRIPTOR)
2290  ((PDVD_DESCRIPTOR_HEADER)dvdReadStructure)->Data;
2291 
2292  // get the media region
2293  RtlZeroMemory (dvdReadStructure, bufferLen);
2294  dvdReadStructure->Format = DvdCopyrightDescriptor;
2295 
2296  // Build and send a request for READ_KEY
2297  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL,
2298  "DevicePickDvdRegion (%p): Getting Copyright Descriptor\n",
2299  Device));
2300 
2301  status = ReadDvdStructure(deviceExtension,
2302  NULL,
2303  dvdReadStructure,
2304  sizeof(DVD_READ_STRUCTURE),
2305  dvdReadStructure,
2307  &bytesReturned);
2308 
2309  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL,
2310  "DevicePickDvdRegion (%p): Got Copyright Descriptor %x\n",
2311  Device, status));
2312 
2313  if ((NT_SUCCESS(status)) &&
2314  (dvdCopyRight->CopyrightProtectionType == 0x01))
2315  {
2316  // keep the media region bitmap around
2317  // a 1 means ok to play
2318  if (dvdCopyRight->RegionManagementInformation == 0xff)
2319  {
2320  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2321  "DevicePickDvdRegion (%p): RegionManagementInformation "
2322  "is set to dis-allow playback for all regions. This is "
2323  "most likely a poorly authored disc. defaulting to all "
2324  "region disc for purpose of choosing initial region\n",
2325  Device));
2326  dvdCopyRight->RegionManagementInformation = 0;
2327  }
2328 
2329  mediaRegion = ~dvdCopyRight->RegionManagementInformation;
2330  }
2331  else
2332  {
2333  // can't automatically pick a default region on a drive without media, so just exit
2334  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
2335  "DevicePickDvdRegion (%p): failed to auto-choose a region due to status %x getting copyright descriptor\n",
2336  Device, status));
2337  goto getout;
2338  }
2339 
2340  // get the device region
2341  RtlZeroMemory (copyProtectKey, bufferLen);
2342  copyProtectKey->KeyLength = DVD_RPC_KEY_LENGTH;
2343  copyProtectKey->KeyType = DvdGetRpcKey;
2344 
2345  // Build and send a request for READ_KEY for RPC key
2346  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL,
2347  "DevicePickDvdRegion (%p): Getting RpcKey\n",
2348  Device));
2349  status = DvdStartSessionReadKey(deviceExtension,
2351  NULL,
2352  copyProtectKey,
2354  copyProtectKey,
2356  &bytesReturned);
2357 
2358  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL,
2359  "DevicePickDvdRegion (%p): Got RpcKey %x\n",
2360  Device, status));
2361 
2362  if (!NT_SUCCESS(status))
2363  {
2364  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
2365  "DevicePickDvdRegion (%p): failed to get RpcKey from "
2366  "a DVD Device\n", Device));
2367  goto getout;
2368  }
2369 
2370  // so we now have what we can get for the media region and the
2371  // drive region. we will not set a region if the drive has one
2372  // set already (mask is not all 1's), nor will we set a region
2373  // if there are no more user resets available.
2374  rpcKey = (PDVD_RPC_KEY)copyProtectKey->KeyData;
2375 
2376  if (rpcKey->RegionMask != 0xff)
2377  {
2378  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2379  "DevicePickDvdRegion (%p): not picking a region since "
2380  "it is already chosen\n", Device));
2381  goto getout;
2382  }
2383 
2384  if (rpcKey->UserResetsAvailable <= 1)
2385  {
2386  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
2387  "DevicePickDvdRegion (%p): not picking a region since "
2388  "only one change remains\n", Device));
2389  goto getout;
2390  }
2391 
2392  // OOBE sets this key based upon the system locale
2393  status = WdfDriverOpenParametersRegistryKey(WdfGetDriver(),
2394  KEY_READ,
2396  &registryKey);
2397 
2398  if (NT_SUCCESS(status))
2399  {
2400  status = WdfRegistryQueryULong(registryKey,
2401  &registryValueName,
2402  &defaultDvdRegion);
2403 
2404  WdfRegistryClose(registryKey);
2405  }
2406 
2407  if (!NT_SUCCESS(status))
2408  {
2409  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
2410  "DevicePickDvdRegion (%p): failed to read registry value due to status %x\n",
2411  Device, status));
2412 
2413  // by default the default Dvd region is 0
2414  defaultDvdRegion = 0;
2416  }
2417 
2418  if (defaultDvdRegion > DVD_MAX_REGION)
2419  {
2420  // the registry has a bogus default
2421  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
2422  "DevicePickDvdRegion (%p): registry has a bogus default "
2423  "region value of %x\n", Device, defaultDvdRegion));
2424 
2425  defaultDvdRegion = 0;
2426  }
2427 
2428  // if defaultDvdRegion == 0, it means no default.
2429 
2430  // we will select the initial dvd region for the user
2431 
2432  if ((defaultDvdRegion != 0) &&
2433  (mediaRegion & (1 << (defaultDvdRegion - 1))))
2434  {
2435  // first choice:
2436  // the media has region that matches
2437  // the default dvd region.
2438  dvdRegion = (1 << (defaultDvdRegion - 1));
2439 
2440  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2441  "DevicePickDvdRegion (%p): Choice #1: media matches "
2442  "drive's default, chose region %x\n", Device, dvdRegion));
2443  }
2444  else if (mediaRegion)
2445  {
2446  // second choice:
2447  // pick the lowest region number from the media
2448  UCHAR mask = 1;
2449  dvdRegion = 0;
2450 
2451  while (mediaRegion && !dvdRegion)
2452  {
2453  // pick the lowest bit
2454  dvdRegion = mediaRegion & mask;
2455  mask <<= 1;
2456  }
2457 
2458  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2459  "DevicePickDvdRegion (%p): Choice #2: choosing lowest "
2460  "media region %x\n", Device, dvdRegion));
2461  }
2462  else if (defaultDvdRegion)
2463  {
2464  // third choice:
2465  // default dvd region from the dvd class installer
2466  dvdRegion = (1 << (defaultDvdRegion - 1));
2467  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2468  "DevicePickDvdRegion (%p): Choice #3: using default "
2469  "region for this install %x\n", Device, dvdRegion));
2470  }
2471  else
2472  {
2473  // unable to pick one for the user -- this should rarely
2474  // happen, since the proppage dvd class installer sets
2475  // the key based upon the system locale
2476  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
2477  "DevicePickDvdRegion (%p): Choice #4: failed to choose "
2478  "a media region\n", Device));
2479  goto getout;
2480  }
2481 
2482  // now that we've chosen a region, set the region by sending the
2483  // appropriate request to the drive
2484  RtlZeroMemory (copyProtectKey, bufferLen);
2485  copyProtectKey->KeyLength = DVD_SET_RPC_KEY_LENGTH;
2486  copyProtectKey->KeyType = DvdSetRpcKey;
2487  dvdRpcKey = (PDVD_SET_RPC_KEY)copyProtectKey->KeyData;
2488  dvdRpcKey->PreferredDriveRegionCode = (UCHAR)~dvdRegion;
2489 
2490  // Build and send request for SEND_KEY
2491  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL,
2492  "DevicePickDvdRegion (%p): Sending new Rpc Key to region %x\n",
2493  Device, dvdRegion));
2494 
2495  status = DvdSendKey(deviceExtension,
2496  NULL,
2497  copyProtectKey,
2499  &bytesReturned);
2500 
2501  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL,
2502  "DevicePickDvdRegion (%p): Sent new Rpc Key %x\n",
2503  Device, status));
2504 
2505  if (!NT_SUCCESS(status))
2506  {
2507  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, "DevicePickDvdRegion (%p): unable to set dvd initial "
2508  " region code (%x)\n", Device, status));
2509  }
2510  else
2511  {
2512  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, "DevicePickDvdRegion (%p): Successfully set dvd "
2513  "initial region\n", Device));
2514 
2515  pickDvdRegion = 0;
2516  }
2517 
2518 getout:
2519  if (dvdReadStructure)
2520  {
2521  FREE_POOL(dvdReadStructure);
2522  }
2523 
2524  // update the new PickDvdRegion value
2525  InterlockedExchange((PLONG)&deviceExtension->DeviceAdditionalData.PickDvdRegion, pickDvdRegion);
2526 
2527  return;
2528 }
2529 
2531 NTSTATUS
2532 DeviceRegisterInterface(
2533  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
2535  )
2536 /*++
2537 Routine Description:
2538 
2539  used to register device class interface or mount device interface
2540 
2541 Arguments:
2542 
2543  DeviceExtension - device context
2544 
2545  InterfaceType - interface type to be registered.
2546 
2547 Return Value:
2548 
2549  NTSTATUS
2550 
2551 --*/
2552 {
2553  NTSTATUS status;
2554  WDFSTRING string = NULL;
2555  GUID* interfaceGuid = NULL;
2556  PUNICODE_STRING savingString = NULL;
2557  BOOLEAN setRestricted = FALSE;
2558  UNICODE_STRING localString;
2559 
2560  PAGED_CODE();
2561 
2562  //Get parameters
2563  switch(InterfaceType)
2564  {
2565  case CdRomDeviceInterface:
2566  interfaceGuid = (LPGUID)&GUID_DEVINTERFACE_CDROM;
2567  setRestricted = TRUE;
2568  savingString = &localString;
2569  break;
2571  interfaceGuid = (LPGUID)&MOUNTDEV_MOUNTED_DEVICE_GUID;
2572  savingString = &(DeviceExtension->MountedDeviceInterfaceName);
2573  break;
2574  default:
2575  return STATUS_INVALID_PARAMETER;
2576  }
2577 
2578  status = WdfDeviceCreateDeviceInterface(DeviceExtension->Device,
2579  interfaceGuid,
2580  NULL);
2581 
2582  if (!NT_SUCCESS(status))
2583  {
2584  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT,
2585  "DeviceRegisterInterface: Unable to register cdrom "
2586  "DCA for fdo %p type: %s [%lx]\n",
2587  DeviceExtension->Device,
2588  (InterfaceType == CdRomDeviceInterface)? "CdRom Interface" : "Mounted Device Interface",
2589  status));
2590  }
2591 
2592  // Retrieve interface string
2593  if (NT_SUCCESS(status))
2594  {
2595  // The string object will be released when its parent object is released.
2596  WDF_OBJECT_ATTRIBUTES attributes;
2597 
2598  WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
2599  attributes.ParentObject = DeviceExtension->Device;
2600 
2601  status = WdfStringCreate(WDF_NO_OBJECT_ATTRIBUTES,
2602  NULL,
2603  &string);
2604  }
2605 
2606  if (NT_SUCCESS(status))
2607  {
2608  status = WdfDeviceRetrieveDeviceInterfaceString(DeviceExtension->Device,
2609  interfaceGuid,
2610  NULL,
2611  string);
2612  }
2613 
2614  if (NT_SUCCESS(status))
2615  {
2616  WdfStringGetUnicodeString(string, savingString);
2617 
2618  if (setRestricted) {
2619 
2620 
2621  WdfObjectDelete(string);
2622  }
2623  }
2624 
2625  return status;
2626 } // end DeviceRegisterInterface()
2627 
2628 
2629 VOID
2630 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
2632  _In_ WDFWORKITEM WorkItem
2633  )
2634 /*++
2635 
2636 Routine Description:
2637 
2638  This workitem is called on a media change when the CDROM device
2639  speed should be restored to the default value.
2640 
2641 Arguments:
2642 
2643  Fdo - Supplies the device object for the CDROM device.
2644  WorkItem - Supplies the pointer to the workitem.
2645 
2646 Return Value:
2647 
2648  None
2649 
2650 --*/
2651 {
2652  NTSTATUS status;
2653  WDFDEVICE device = WdfWorkItemGetParentObject(WorkItem);
2654  PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(device);
2655  PPERFORMANCE_DESCRIPTOR perfDescriptor;
2656  ULONG transferLength = sizeof(PERFORMANCE_DESCRIPTOR);
2657  SCSI_REQUEST_BLOCK srb = {0};
2658  PCDB cdb = (PCDB)srb.Cdb;
2659 
2660  PAGED_CODE();
2661 
2662  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DeviceRestoreDefaultSpeed: Restore device speed for %p\n", device));
2663 
2664  perfDescriptor = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
2665  transferLength,
2667  if (perfDescriptor == NULL)
2668  {
2669  return;
2670  }
2671 
2672  RtlZeroMemory(perfDescriptor, transferLength);
2673 
2674  perfDescriptor->RestoreDefaults = TRUE;
2675 
2676  srb.TimeOutValue = deviceExtension->TimeOutValue;
2677 
2678  srb.CdbLength = 12;
2679  cdb->SET_STREAMING.OperationCode = SCSIOP_SET_STREAMING;
2680  REVERSE_BYTES_SHORT(&cdb->SET_STREAMING.ParameterListLength, &transferLength);
2681 
2682  status = DeviceSendSrbSynchronously(device,
2683  &srb,
2684  perfDescriptor,
2685  transferLength,
2686  TRUE,
2687  NULL);
2688  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2689  "DeviceRestoreDefaultSpeed: Set Streaming command completed with status: 0x%X\n", status));
2690 
2691  FREE_POOL(perfDescriptor);
2692  WdfObjectDelete(WorkItem);
2693 
2694  return;
2695 }
2696 
2697 // custom string match -- careful!
2699 BOOLEAN
2700 StringsAreMatched(
2701  _In_opt_z_ PCHAR StringToMatch,
2703  )
2704 /*++
2705 
2706 Routine Description:
2707 
2708  compares if two strings are identical
2709 
2710 Arguments:
2711 
2712  StringToMatch - source string.
2713  TargetString - target string.
2714 
2715 Return Value:
2716 
2717  BOOLEAN - TRUE (identical); FALSE (not match)
2718 
2719 --*/
2720 {
2721  size_t length;
2722 
2723  PAGED_CODE();
2724 
2726 
2727  // if no match requested, return TRUE
2728  if (StringToMatch == NULL)
2729  {
2730  return TRUE;
2731  }
2732 
2733  // cache the string length for efficiency
2734  length = strlen(StringToMatch);
2735 
2736  // ZERO-length strings may only match zero-length strings
2737  if (length == 0)
2738  {
2739  return (strlen(TargetString) == 0);
2740  }
2741 
2742  // strncmp returns zero if the strings match
2743  return (strncmp(StringToMatch, TargetString, length) == 0);
2744 }
2745 
2746 
2747 NTSTATUS
2749  _In_ WDFREQUEST Request,
2751  )
2752 /*++
2753 
2754 Routine Description:
2755 
2756  set the request object context fields
2757 
2758 Arguments:
2759 
2760  Request - request object.
2761  Handler - the function that finally handles this request.
2762 
2763 Return Value:
2764 
2765  NTSTATUS
2766 
2767 --*/
2768 {
2770  PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(Request);
2771  PKEVENT syncEvent = NULL;
2772 
2773  syncEvent = ExAllocatePoolWithTag(NonPagedPoolNx,
2774  sizeof(KEVENT),
2776 
2777  if (syncEvent == NULL)
2778  {
2779  // memory allocation failed.
2781  }
2782  else
2783  {
2784  // now, put the special synchronization information into the context
2785  requestContext->SyncRequired = TRUE;
2786  requestContext->SyncEvent = syncEvent;
2787  requestContext->SyncCallback = Handler;
2788 
2790  }
2791 
2792  return status;
2793 }
2794 
2795 
2796 NTSTATUS
2798  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
2799  _In_ WDFREQUEST Request,
2801  _Out_ size_t * DataLength
2802  )
2803 /*++
2804 
2805 Routine Description:
2806 
2807 
2808 
2809 Arguments:
2810 
2811  DeviceExtension - device context
2812  Request - request object.
2813  RequestParameters - request parameter
2814  DataLength - transferred data length.
2815 
2816 Return Value:
2817 
2818  NTSTATUS
2819 
2820 --*/
2821 {
2823  PSTORAGE_DEVICE_ID_DESCRIPTOR deviceIdDescriptor = NULL;
2824  PSTORAGE_DESCRIPTOR_HEADER descHeader = NULL;
2826 
2827  *DataLength = 0;
2828 
2829  // Get the VPD page 83h data.
2830  status = DeviceRetrieveDescriptor(DeviceExtension->Device,
2831  &propertyId,
2832  (PSTORAGE_DESCRIPTOR_HEADER*)&deviceIdDescriptor);
2833 
2834  if (NT_SUCCESS(status) && (deviceIdDescriptor == NULL))
2835  {
2837  }
2838 
2839  if (NT_SUCCESS(status))
2840  {
2841  status = WdfRequestRetrieveOutputBuffer(Request,
2842  RequestParameters.Parameters.DeviceIoControl.OutputBufferLength,
2843  &descHeader,
2844  NULL);
2845  }
2846 
2847  if (NT_SUCCESS(status))
2848  {
2850  ULONG offset = descHeader->Size;
2851  PUCHAR dest = (PUCHAR)descHeader + offset;
2852  size_t outputBufferSize;
2853 
2854  outputBufferSize = RequestParameters.Parameters.DeviceIoControl.OutputBufferLength;
2855 
2856  // Adjust required size and potential destination location.
2857  status = RtlULongAdd(descHeader->Size, deviceIdDescriptor->Size, &descHeader->Size);
2858 
2859  if (NT_SUCCESS(status) &&
2860  (outputBufferSize < descHeader->Size))
2861  {
2862  // Output buffer is too small. Return error and make sure
2863  // the caller gets info about required buffer size.
2864  *DataLength = descHeader->Size;
2866  }
2867 
2868  if (NT_SUCCESS(status))
2869  {
2870  storageDuid = (PSTORAGE_DEVICE_UNIQUE_IDENTIFIER)descHeader;
2871  storageDuid->StorageDeviceIdOffset = offset;
2872 
2874  deviceIdDescriptor,
2875  deviceIdDescriptor->Size);
2876 
2877  *DataLength = storageDuid->Size;
2879  }
2880 
2881  FREE_POOL(deviceIdDescriptor);
2882  }
2883 
2884  return status;
2885 }
2886 
2887 NTSTATUS
2889  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
2890  _In_ WDFREQUEST Request,
2892  _Out_ size_t * DataLength
2893  )
2894 /*++
2895 
2896 Routine Description:
2897 
2898 
2899 
2900 Arguments:
2901 
2902  DeviceExtension - device context
2903  Request - request object.
2904  RequestParameters - request parameter
2905  DataLength - transferred data length.
2906 
2907 Return Value:
2908 
2909  NTSTATUS
2910 
2911 --*/
2912 {
2914  PSTORAGE_DEVICE_DESCRIPTOR deviceDescriptor = DeviceExtension->DeviceDescriptor;
2915  PSTORAGE_DESCRIPTOR_HEADER descHeader = NULL;
2917  PUCHAR dest = NULL;
2918 
2919  if (deviceDescriptor == NULL)
2920  {
2922  }
2923 
2924  if (NT_SUCCESS(status))
2925  {
2926  status = WdfRequestRetrieveOutputBuffer(Request,
2927  RequestParameters.Parameters.DeviceIoControl.OutputBufferLength,
2928  &descHeader,
2929  NULL);
2930  }
2931 
2932  if (NT_SUCCESS(status) &&
2933  (deviceDescriptor->SerialNumberOffset == 0))
2934  {
2936  }
2937 
2938  // Use this info only if serial number is available.
2939  if (NT_SUCCESS(status))
2940  {
2941  ULONG offset = descHeader->Size;
2942  size_t outputBufferSize = RequestParameters.Parameters.DeviceIoControl.OutputBufferLength;
2943 
2944  // Adjust required size and potential destination location.
2945  dest = (PUCHAR)descHeader + offset;
2946 
2947  status = RtlULongAdd(descHeader->Size, deviceDescriptor->Size, &descHeader->Size);
2948 
2949  if (NT_SUCCESS(status) &&
2950  (outputBufferSize < descHeader->Size))
2951  {
2952  // Output buffer is too small. Return error and make sure
2953  // the caller get info about required buffer size.
2954  *DataLength = descHeader->Size;
2956  }
2957 
2958  if (NT_SUCCESS(status))
2959  {
2960  storageDuid = (PSTORAGE_DEVICE_UNIQUE_IDENTIFIER)descHeader;
2961  storageDuid->StorageDeviceOffset = offset;
2962 
2964  deviceDescriptor,
2965  deviceDescriptor->Size);
2966 
2967  *DataLength = storageDuid->Size;
2969  }
2970  }
2971 
2972  return status;
2973 }
2974 
2976 ULONG
2977 DeviceRetrieveModeSenseUsingScratch(
2978  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
2979  _In_reads_bytes_(Length) PCHAR ModeSenseBuffer,
2980  _In_ ULONG Length,
2983  )
2984 /*++
2985 
2986 Routine Description:
2987 
2988  retrieve mode sense informaiton of the device
2989 
2990 Arguments:
2991 
2992  DeviceExtension - device context
2993  ModeSenseBuffer - buffer to savee the mode sense info.
2994  Length - buffer length
2995  PageCode - .
2996  PageControl -
2997 
2998 Return Value:
2999 
3000  ULONG - transferred data length
3001 
3002 --*/
3003 {
3005  ULONG transferSize = min(Length, DeviceExtension->ScratchContext.ScratchBufferSize);
3006  CDB cdb;
3007 
3008  PAGED_CODE();
3009 
3010  ScratchBuffer_BeginUse(DeviceExtension);
3011 
3012  RtlZeroMemory(&cdb, sizeof(CDB));
3013  // Set up the CDB
3014  cdb.MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
3015  cdb.MODE_SENSE.PageCode = PageCode;
3016  cdb.MODE_SENSE.Pc = PageControl;
3017  cdb.MODE_SENSE.AllocationLength = (UCHAR)transferSize;
3018 
3019  status = ScratchBuffer_ExecuteCdb(DeviceExtension, NULL, transferSize, TRUE, &cdb, 6);
3020 
3021  if (NT_SUCCESS(status))
3022  {
3023  transferSize = min(Length, DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength);
3024  RtlCopyMemory(ModeSenseBuffer,
3025  DeviceExtension->ScratchContext.ScratchBuffer,
3026  transferSize);
3027  }
3028 
3029  ScratchBuffer_EndUse(DeviceExtension);
3030 
3031  return transferSize;
3032 }
3033 
3035 PVOID
3036 ModeSenseFindSpecificPage(
3037  _In_reads_bytes_(Length) PCHAR ModeSenseBuffer,
3038  _In_ size_t Length,
3040  _In_ BOOLEAN Use6BytesCdb
3041  )
3042 /*++
3043 
3044 Routine Description:
3045 
3046  This routine scans through the mode sense data and finds the requested
3047  mode sense page code.
3048 
3049 Arguments:
3050  ModeSenseBuffer - Supplies a pointer to the mode sense data.
3051 
3052  Length - Indicates the length of valid data.
3053 
3054  PageMode - Supplies the page mode to be searched for.
3055 
3056  Use6BytesCdb - Indicates whether 6 or 10 byte mode sense was used.
3057 
3058 Return Value:
3059 
3060  A pointer to the the requested mode page. If the mode page was not found
3061  then NULL is return.
3062 
3063 --*/
3064 {
3065  PCHAR limit;
3066  ULONG parameterHeaderLength;
3067  PVOID result = NULL;
3068 
3069  PAGED_CODE();
3070 
3071  limit = ModeSenseBuffer + Length;
3072  parameterHeaderLength = (Use6BytesCdb)
3073  ? sizeof(MODE_PARAMETER_HEADER)
3074  : sizeof(MODE_PARAMETER_HEADER10);
3075 
3076  if (Length >= parameterHeaderLength)
3077  {
3078  PMODE_PARAMETER_HEADER10 modeParam10;
3079  ULONG blockDescriptorLength;
3080 
3081  // Skip the mode select header and block descriptors.
3082  if (Use6BytesCdb)
3083  {
3084  blockDescriptorLength = ((PMODE_PARAMETER_HEADER)ModeSenseBuffer)->BlockDescriptorLength;
3085  }
3086  else
3087  {
3088  modeParam10 = (PMODE_PARAMETER_HEADER10) ModeSenseBuffer;
3089  blockDescriptorLength = modeParam10->BlockDescriptorLength[1];
3090  }
3091 
3092  ModeSenseBuffer += parameterHeaderLength + blockDescriptorLength;
3093 
3094  // ModeSenseBuffer now points at pages. Walk the pages looking for the
3095  // requested page until the limit is reached.
3096  while (ModeSenseBuffer +
3098  {
3099  if (((PMODE_DISCONNECT_PAGE) ModeSenseBuffer)->PageCode == PageMode)
3100  {
3101  // found the mode page. make sure it's safe to touch it all
3102  // before returning the pointer to caller
3103  if (ModeSenseBuffer + ((PMODE_DISCONNECT_PAGE)ModeSenseBuffer)->PageLength > limit)
3104  {
3105  // Return NULL since the page is not safe to access in full
3106  result = NULL;
3107  }
3108  else
3109  {
3110  result = ModeSenseBuffer;
3111  }
3112  break;
3113  }
3114 
3115  // Advance to the next page which is 4-byte-aligned offset after this page.
3116  ModeSenseBuffer += ((PMODE_DISCONNECT_PAGE) ModeSenseBuffer)->PageLength +
3118  }
3119  }
3120 
3121  return result;
3122 } // end ModeSenseFindSpecificPage()
3123 
3124 
3126 NTSTATUS
3127 PerformEjectionControl(
3128  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
3129  _In_ WDFREQUEST Request,
3131  _In_ BOOLEAN Lock
3132  )
3133 /*++
3134 
3135 Routine Description:
3136 
3137  ejection control process
3138 
3139 Arguments:
3140 
3141  DeviceExtension - device extension
3142  Request - WDF request to be used for communication with the device
3143  LockType - the type of lock
3144  Lock - if TRUE, lock the device; if FALSE, unlock it
3145 
3146 Return Value:
3147 
3148  NTSTATUS
3149 
3150 --*/
3151 {
3152  NTSTATUS status;
3153  PFILE_OBJECT_CONTEXT fileObjectContext = NULL;
3154  SCSI_REQUEST_BLOCK srb;
3155  PCDB cdb = NULL;
3156 
3157  LONG newLockCount = 0;
3158  LONG newProtectedLockCount = 0;
3159  LONG newInternalLockCount = 0;
3160  LONG newFileLockCount = 0;
3161  BOOLEAN countChanged = FALSE;
3162  BOOLEAN previouslyLocked = FALSE;
3163  BOOLEAN nowLocked = FALSE;
3164 
3165  PAGED_CODE();
3166 
3167  // Prevent race conditions while working with lock counts
3168  status = WdfWaitLockAcquire(DeviceExtension->EjectSynchronizationLock, NULL);
3169  if (!NT_SUCCESS(status))
3170  {
3171  NT_ASSERT(FALSE);
3172  }
3173 
3174  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
3175  "PerformEjectionControl: "
3176  "Received request for %s lock type\n",
3178  ));
3179 
3180 
3181  // If this is a "secured" request, retrieve the file object context
3182  if (LockType == SecureMediaLock)
3183  {
3184  WDFFILEOBJECT fileObject = NULL;
3185 
3186  fileObject = WdfRequestGetFileObject(Request);
3187 
3188  if (fileObject == NULL)
3189  {
3191 
3192  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL,
3193  "FileObject does not match to the one in IRP_MJ_CREATE, KMDF returns NULL\n"));
3194  goto Exit;
3195  }
3196 
3197  fileObjectContext = FileObjectGetContext(fileObject);
3198  NT_ASSERT(fileObjectContext != NULL);
3199  }
3200 
3201  // Lock counts should never fall below 0
3202  NT_ASSERT(DeviceExtension->LockCount >= 0);
3203  NT_ASSERT(DeviceExtension->ProtectedLockCount >= 0);
3204  NT_ASSERT(DeviceExtension->InternalLockCount >= 0);
3205 
3206  // Get the current lock counts
3207  newLockCount = DeviceExtension->LockCount;
3208  newProtectedLockCount = DeviceExtension->ProtectedLockCount;
3209  newInternalLockCount = DeviceExtension->InternalLockCount;
3210  if (fileObjectContext)
3211  {
3212  // fileObjectContext->LockCount is ULONG and should always >= 0
3213  newFileLockCount = fileObjectContext->LockCount;
3214  }
3215 
3216  // Determine which lock counts need to be changed and how
3217  if (Lock && LockType == SimpleMediaLock)
3218  {
3219  newLockCount++;
3220  countChanged = TRUE;
3221  }
3222  else if (Lock && LockType == SecureMediaLock)
3223  {
3224  newFileLockCount++;
3225  newProtectedLockCount++;
3226  countChanged = TRUE;
3227  }
3228  else if (Lock && LockType == InternalMediaLock)
3229  {
3230  newInternalLockCount++;
3231  countChanged = TRUE;
3232  }
3233  else if (!Lock && LockType == SimpleMediaLock)
3234  {
3235  if (newLockCount != 0)
3236  {
3237  newLockCount--;
3238  countChanged = TRUE;
3239  }
3240  }
3241  else if (!Lock && LockType == SecureMediaLock)
3242  {
3243  if ( (newFileLockCount == 0) || (newProtectedLockCount == 0) )
3244  {
3246  goto Exit;
3247  }
3248  newFileLockCount--;
3249  newProtectedLockCount--;
3250  countChanged = TRUE;
3251  }
3252  else if (!Lock && LockType == InternalMediaLock)
3253  {
3254  NT_ASSERT(newInternalLockCount != 0);
3255  newInternalLockCount--;
3256  countChanged = TRUE;
3257  }
3258 
3259  if ( (DeviceExtension->LockCount != 0) ||
3260  (DeviceExtension->ProtectedLockCount != 0) ||
3261  (DeviceExtension->InternalLockCount != 0) )
3262  {
3263  previouslyLocked = TRUE;
3264  }
3265  if ( (newLockCount != 0) ||
3266  (newProtectedLockCount != 0) ||
3267  (newInternalLockCount != 0) )
3268  {
3269  nowLocked = TRUE;
3270  }
3271 
3272  // Only send command down to device when necessary
3273  if (previouslyLocked != nowLocked)
3274  {
3275  // Compose and send the PREVENT ALLOW MEDIA REMOVAL command.
3276  RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
3277 
3278  srb.CdbLength = 6;
3279  srb.TimeOutValue = DeviceExtension->TimeOutValue;
3280 
3281  cdb = (PCDB)&srb.Cdb;
3282  cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
3283  cdb->MEDIA_REMOVAL.Prevent = Lock;
3284 
3285  status = DeviceSendSrbSynchronously(DeviceExtension->Device,
3286  &srb,
3287  NULL,
3288  0,
3289  FALSE,
3290  Request);
3291  }
3292 
3293 Exit:
3294 
3295  // Store the updated lock counts on success
3296  if (countChanged && NT_SUCCESS(status))
3297  {
3298  DeviceExtension->LockCount = newLockCount;
3299  DeviceExtension->ProtectedLockCount = newProtectedLockCount;
3300  DeviceExtension->InternalLockCount = newInternalLockCount;
3301  if (fileObjectContext)
3302  {
3303  fileObjectContext->LockCount = newFileLockCount;
3304  }
3305  }
3306 
3307  WdfWaitLockRelease(DeviceExtension->EjectSynchronizationLock);
3308 
3309  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
3310  "PerformEjectionControl: %!STATUS!, "
3311  "Count Changed: %d, Command Sent: %d, "
3312  "Current Counts: Internal: %x Secure: %x Simple: %x\n",
3313  status,
3314  countChanged,
3315  previouslyLocked != nowLocked,
3316  DeviceExtension->InternalLockCount,
3317  DeviceExtension->ProtectedLockCount,
3318  DeviceExtension->LockCount
3319  ));
3320 
3321  return status;
3322 }
3323 
3324 
3326 NTSTATUS
3327 DeviceUnlockExclusive(
3328  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
3329  _In_ WDFFILEOBJECT FileObject,
3331  )
3332 /*++
3333 
3334 Routine Description:
3335 
3336  to unlock the exclusive lock
3337 
3338 Arguments:
3339 
3340  DeviceExtension - device context
3341  FileObject - file object that currently holds the lock
3342  IgnorePreviousMediaChanges - if TRUE, ignore previously accumulated media changes
3343 
3344 Return Value:
3345 
3346  NTSTATUS
3347 
3348 --*/
3349 {
3351  PCDROM_DATA cdData = &DeviceExtension->DeviceAdditionalData;
3352  PMEDIA_CHANGE_DETECTION_INFO info = DeviceExtension->MediaChangeDetectionInfo;
3353  BOOLEAN ANPending = 0;
3354  LONG requestInUse = 0;
3355 
3356  PAGED_CODE();
3357 
3358  if (!EXCLUSIVE_MODE(cdData))
3359  {
3360  // Device is not locked for exclusive access.
3361  // Can not process unlock request.
3362  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL,
3363  "RequestHandleExclusiveAccessUnlockDevice: Device not locked for exclusive access, can't unlock device.\n"));
3365  }
3366  else if (!EXCLUSIVE_OWNER(cdData, FileObject))
3367  {
3368  // Request not from the exclusive owner, can't unlock the device.
3369  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL,
3370  "RequestHandleExclusiveAccessUnlockDevice: Unable to unlock device, invalid file object\n"));
3371 
3373  }
3374 
3375  if (NT_SUCCESS(status))
3376  {
3377  // Unless we were explicitly requested not to do so, generate a media removal notification
3378  // followed by a media arrival notification similar to volume lock/unlock file system events.
3380  {
3381  MEDIA_CHANGE_DETECTION_STATE previousMediaState = MediaUnknown;
3382 
3383  // Change the media state to "unavailable", which will cause a removal notification if the media
3384  // was previously present. At the same time, store the previous state in previousMediaState.
3385  DeviceSetMediaChangeStateEx(DeviceExtension, MediaUnavailable, &previousMediaState);
3386  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
3387  "DeviceUnlockExclusive: Changing the media state to MediaUnavailable\n"));
3388 
3389  // Restore the previous media state, which will cause a media arrival notification if the media
3390  // was originally present.
3391  DeviceSetMediaChangeStateEx(DeviceExtension, previousMediaState, NULL);
3392  }
3393 
3394  // Set DO_VERIFY_VOLUME so that the file system will remount on it.
3395  if (IsVolumeMounted(DeviceExtension->DeviceObject))
3396  {
3397  SET_FLAG(DeviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME);
3398  }
3399 
3400  // Set MMC state to update required
3401  cdData->Mmc.WriteAllowed = FALSE;
3403 
3404  // Send unlock notification
3405  DeviceSendNotification(DeviceExtension,
3406  &GUID_IO_CDROM_EXCLUSIVE_UNLOCK,
3407  0,
3408  NULL);
3409 
3411 
3412  if ((info != NULL) && (info->AsynchronousNotificationSupported != FALSE))
3413  {
3414  ANPending = info->ANSignalPendingDueToExclusiveLock;
3415  info->ANSignalPendingDueToExclusiveLock = FALSE;
3416 
3417  if ((ANPending != FALSE) && (info->MediaChangeDetectionDisableCount == 0))
3418  {
3419  // if the request is not in use, mark it as such.
3420  requestInUse = InterlockedCompareExchange((PLONG)&info->MediaChangeRequestInUse, 1, 0);
3421 
3422  if (requestInUse == 0)
3423  {
3424  // The last MCN finished. ok to issue the new one.
3425  RequestSetupMcnSyncIrp(DeviceExtension);
3426 
3427  // The irp will go into KMDF framework and a request will be created there to represent it.
3428  IoCallDriver(DeviceExtension->DeviceObject, info->MediaChangeSyncIrp);
3429  }
3430  }
3431  }
3432  }
3433 
3434  return status;
3435 }
3436 
3437 
3438 VOID
3440  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
3441  _In_ WDFREQUEST Request,
3444  )
3445 {
3446 #ifdef DBG
3447  ULONG ioctlCode = 0;
3448  WDF_REQUEST_PARAMETERS requestParameters;
3449 
3450  // Get the Request parameters
3451  WDF_REQUEST_PARAMETERS_INIT(&requestParameters);
3452  WdfRequestGetParameters(Request, &requestParameters);
3453 
3454  if (requestParameters.Type == WdfRequestTypeDeviceControl)
3455  {
3456  ioctlCode = requestParameters.Parameters.DeviceIoControl.IoControlCode;
3457 
3458  if (requestParameters.Parameters.DeviceIoControl.IoControlCode != IOCTL_MCN_SYNC_FAKE_IOCTL)
3459  {
3460  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
3461  "Request complete - IOCTL - code: %X; Status: %X; Information: %X\n",
3462  ioctlCode,
3463  Status,
3464  (ULONG)Information));
3465  }
3466  else
3467  {
3468  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL,
3469  "Request complete - IOCTL - code: %X; Status: %X; Information: %X\n",
3470  ioctlCode,
3471  Status,
3472  (ULONG)Information));
3473  }
3474  }
3475  else if (requestParameters.Type == WdfRequestTypeRead)
3476  {
3477  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
3478  "Request complete - READ - Starting Offset: %X; Length: %X; Transferred Length: %X; Status: %X\n",
3479  (ULONG)requestParameters.Parameters.Read.DeviceOffset,
3480  (ULONG)requestParameters.Parameters.Read.Length,
3481  (ULONG)Information,
3482  Status));
3483  }
3484  else if (requestParameters.Type == WdfRequestTypeWrite)
3485  {
3486  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
3487  "Request complete - WRITE - Starting Offset: %X; Length: %X; Transferred Length: %X; Status: %X\n",
3488  (ULONG)requestParameters.Parameters.Write.DeviceOffset,
3489  (ULONG)requestParameters.Parameters.Write.Length,
3490  (ULONG)Information,
3491  Status));
3492  }
3493 #endif
3494 
3496  {
3497  PIRP irp = WdfRequestWdmGetIrp(Request);
3498  if (irp->Tail.Overlay.Thread)
3499  {
3500  IoSetHardErrorOrVerifyDevice(irp, DeviceExtension->DeviceObject);
3501  }
3502  }
3503 
3504  if (!NT_SUCCESS(Status) && DeviceExtension->SurpriseRemoved == TRUE)
3505  {
3506  // IMAPI expects ERROR_DEV_NOT_EXISTS if recorder has been surprised removed,
3507  // or it will retry WRITE commands for up to 3 minutes
3508  // CDROM behavior should be consistent for all requests, including SCSI pass-through
3510  }
3511 
3512  WdfRequestCompleteWithInformation(Request, Status, Information);
3513 
3514  return;
3515 }
3516 
3517 
3518 VOID
3519 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
3521  _In_ WDFREQUEST Request,
3522  _In_ WDFIOTARGET Target,
3525  )
3526 /*++
3527 
3528 Routine Description:
3529 
3530  This is a dummy competion routine that simply calls WdfRequestComplete. We have to use
3531  this dummy competion routine instead of WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET, because
3532  the latter causes the framework to not check if the I/O target is closed or not.
3533 
3534 Arguments:
3535 
3536  Request - completed request
3537  Target - the I/O target that completed the request
3538  Params - request parameters
3539  Context - not used
3540 
3541 Return Value:
3542 
3543  none
3544 
3545 --*/
3546 {
3550 
3551  WdfRequestCompleteWithInformation(Request,
3552  WdfRequestGetStatus(Request),
3553  WdfRequestGetInformation(Request));
3554 }
3555 
3556 
3558 NTSTATUS
3559 DeviceSendPowerDownProcessRequest(
3560  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
3563  )
3564 /*++
3565 
3566 Routine Description:
3567 
3568  This function is called during processing power down request.
3569  It is used to send either SYNC CACHE command or STOP UNIT command.
3570 
3571  Caller should set proper value in deviceExtension->PowerContext.PowerChangeState.PowerDown
3572  to trigger the correct command be sent.
3573 
3574 Arguments:
3575 
3576  DeviceExtension -
3577 
3578  CompletionRoutine - Completion routine that needs to be set for the request
3579 
3580  Context - Completion context associated with the completion routine
3581 
3582 Return Value:
3583 
3584  NTSTATUS
3585 
3586 --*/
3587 {
3588  NTSTATUS status;
3589  BOOLEAN requestSent = FALSE;
3590 
3591  BOOLEAN shouldRetry = TRUE;
3592  PCDB cdb = (PCDB)DeviceExtension->PowerContext.Srb.Cdb;
3593  ULONG timeoutValue = DeviceExtension->TimeOutValue;
3594  ULONG retryCount = 1;
3595 
3596  // reset some fields.
3597  DeviceExtension->PowerContext.RetryIntervalIn100ns = 0;
3598  status = PowerContextReuseRequest(DeviceExtension);
3599  RequestClearSendTime(DeviceExtension->PowerContext.PowerRequest);
3600 
3601  if (!NT_SUCCESS(status))
3602  {
3603  return status;
3604  }
3605 
3606  // set proper timeout value and max retry count.
3607  switch(DeviceExtension->PowerContext.PowerChangeState.PowerDown)
3608  {
3612  break;
3613 
3614  case PowerDownDeviceLocked:
3615  // Case of issuing SYNC CACHE command. Do not use power irp timeout remaining time in this case
3616  // as we want to give best try on SYNC CACHE command.
3617  retryCount = MAXIMUM_RETRIES;
3618  timeoutValue = DeviceExtension->TimeOutValue;
3619  break;
3620 
3622  {
3623  // Case of issuing STOP UNIT command
3624  // As "Imme" bit is set to '1', this command should be completed in short time.
3625  // This command is at low importance, failure of this command has very small impact.
3626  ULONG secondsRemaining = 0;
3627 
3628 #if (WINVER >= 0x0601)
3629  // this API is introduced in Windows7
3630  PoQueryWatchdogTime(DeviceExtension->LowerPdo, &secondsRemaining);
3631 #endif
3632 
3633  if (secondsRemaining == 0)
3634  {
3635  // not able to retrieve remaining time from PoQueryWatchdogTime API, use default values.
3636  retryCount = MAXIMUM_RETRIES;
3637  timeoutValue = SCSI_CDROM_TIMEOUT;
3638  }
3639  else
3640  {
3641  // plan to leave about 30 seconds to lower level drivers if possible.
3642  if (secondsRemaining >= 32)
3643  {
3644  retryCount = (secondsRemaining - 30)/SCSI_CDROM_TIMEOUT + 1;
3645  timeoutValue = SCSI_CDROM_TIMEOUT;
3646 
3647  if (retryCount > MAXIMUM_RETRIES)
3648  {
3649  retryCount = MAXIMUM_RETRIES;
3650  }
3651 
3652  if (retryCount == 1)
3653  {
3654  timeoutValue = secondsRemaining - 30;
3655  }
3656  }
3657  else
3658  {
3659  // issue the command with minimal timeout value and do not retry on it.
3660  retryCount = 1;
3661  timeoutValue = 2;
3662  }
3663  }
3664  }
3665  break;
3666  default:
3667  NT_ASSERT( FALSE );
3669  return status;
3670  }
3671 
3672  DeviceExtension->PowerContext.RetryCount = retryCount;
3673 
3674  // issue command.
3675  while (shouldRetry)
3676  {
3677 
3678  // set SRB fields.
3679  DeviceExtension->PowerContext.Srb.SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER |
3684 
3685  DeviceExtension->PowerContext.Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
3686  DeviceExtension->PowerContext.Srb.TimeOutValue = timeoutValue;
3687 
3688  if (DeviceExtension->PowerContext.PowerChangeState.PowerDown == PowerDownDeviceInitial)
3689  {
3690  DeviceExtension->PowerContext.Srb.Function = SRB_FUNCTION_LOCK_QUEUE;
3691  }
3692  else if (DeviceExtension->PowerContext.PowerChangeState.PowerDown == PowerDownDeviceLocked)
3693  {
3694  DeviceExtension->PowerContext.Srb.Function = SRB_FUNCTION_QUIESCE_DEVICE;
3695  }
3696  else if (DeviceExtension->PowerContext.PowerChangeState.PowerDown == PowerDownDeviceQuiesced)
3697  {
3698  // Case of issuing SYNC CACHE command.
3699  DeviceExtension->PowerContext.Srb.CdbLength = 10;
3700  cdb->SYNCHRONIZE_CACHE10.OperationCode = SCSIOP_SYNCHRONIZE_CACHE;
3701  }
3702  else if (DeviceExtension->PowerContext.PowerChangeState.PowerDown == PowerDownDeviceFlushed)
3703  {
3704  // Case of issuing STOP UNIT command.
3705  DeviceExtension->PowerContext.Srb.CdbLength = 6;
3706  cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
3707  cdb->START_STOP.Start = 0;
3708  cdb->START_STOP.Immediate = 1;
3709  }
3710  else if (DeviceExtension->PowerContext.PowerChangeState.PowerDown == PowerDownDeviceStopped)
3711  {
3712  DeviceExtension->PowerContext.Srb.Function = SRB_FUNCTION_UNLOCK_QUEUE;
3713  }
3714 
3715  // Set up completion routine and context if requested
3716  if (CompletionRoutine)
3717  {
3718  WdfRequestSetCompletionRoutine(DeviceExtension->PowerContext.PowerRequest,
3720  Context);
3721  }
3722 
3723  status = RequestSend(DeviceExtension,
3724  DeviceExtension->PowerContext.PowerRequest,
3725  DeviceExtension->IoTarget,
3727  &requestSent);
3728 
3729  if (requestSent)
3730  {
3731  if ((CompletionRoutine == NULL) &&
3732  (SRB_STATUS(DeviceExtension->PowerContext.Srb.SrbStatus) != SRB_STATUS_SUCCESS))
3733  {
3734  TracePrint((TRACE_LEVEL_ERROR,
3735  TRACE_FLAG_POWER,
3736  "%p\tError occured when issuing %s command to device. Srb %p, Status %x\n",
3737  DeviceExtension->PowerContext.PowerRequest,
3738  (DeviceExtension->PowerContext.PowerChangeState.PowerDown == PowerDownDeviceQuiesced) ? "SYNC CACHE" : "STOP UNIT",
3739  &DeviceExtension->PowerContext.Srb,
3740  DeviceExtension->PowerContext.Srb.SrbStatus));
3741 
3742  NT_ASSERT(!(TEST_FLAG(DeviceExtension->PowerContext.Srb.SrbStatus, SRB_STATUS_QUEUE_FROZEN)));
3743 
3744  shouldRetry = RequestSenseInfoInterpret(DeviceExtension,
3745  DeviceExtension->PowerContext.PowerRequest,
3746  &(DeviceExtension->PowerContext.Srb),
3747  retryCount - DeviceExtension->PowerContext.RetryCount,
3748  &status,
3749  &(DeviceExtension->PowerContext.RetryIntervalIn100ns));
3750 
3751  if (shouldRetry && (DeviceExtension->PowerContext.RetryCount-- == 0))
3752  {
3753  shouldRetry = FALSE;
3754  }
3755  }
3756  else
3757  {
3758  // succeeded, do not need to retry.
3759  shouldRetry = FALSE;
3760  }
3761 
3762  }
3763  else
3764  {
3765  // request failed to be sent
3766  shouldRetry = FALSE;
3767  }
3768 
3769  if (shouldRetry)
3770  {
3771  LARGE_INTEGER t;
3772  t.QuadPart = -DeviceExtension->PowerContext.RetryIntervalIn100ns;
3774 
3775  status = PowerContextReuseRequest(DeviceExtension);
3776  if (!NT_SUCCESS(status))
3777  {
3778  shouldRetry = FALSE;
3779  }
3780  }
3781  }
3782 
3783  if (DeviceExtension->PowerContext.PowerChangeState.PowerDown == PowerDownDeviceQuiesced)
3784  {
3785  // record SYNC CACHE command completion time stamp.
3786  KeQueryTickCount(&DeviceExtension->PowerContext.Step1CompleteTime);
3787  }
3788 
3789  return status;
3790 }
3791 
3792 NTSTATUS
3794  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
3795  _In_ WDFREQUEST Request,
3796  _In_ WDFIOTARGET IoTarget,
3797  _In_ ULONG Flags,
3798  _Out_opt_ PBOOLEAN RequestSent
3799  )
3800 /*++
3801 
3802 Routine Description:
3803 
3804  Send the request to the target, wake up the device from Zero Power state if necessary.
3805 
3806 Arguments:
3807 
3808  DeviceExtension - device extension
3809  Request - the request to be sent
3810  IoTarget - target of the above request
3811  Flags - flags for the operation
3812  RequestSent - optional, if the request was sent
3813 
3814 Return Value:
3815 
3816  NTSTATUS
3817 
3818 --*/
3819 {
3821  BOOLEAN requestSent = FALSE;
3823 
3824  UNREFERENCED_PARAMETER(DeviceExtension);
3825 
3826  if ((DeviceExtension->ZeroPowerODDInfo != NULL) &&
3827  (DeviceExtension->ZeroPowerODDInfo->InZeroPowerState != FALSE))
3828  {
3829  }
3830 
3831  // Now send down the request
3832  if (NT_SUCCESS(status))
3833  {
3835 
3837 
3838  // send request and check status
3839 
3840  // Disable SDV warning about infinitely waiting in caller's context:
3841  // 1. Some requests (such as SCSI_PASS_THROUGH, contains buffer from user space) need to be sent down in caller’s context.
3842  // Consequently, these requests wait in caller’s context until they are allowed to be sent down.
3843  // 2. Considering the situation that during sleep, a request can be hold by storage port driver. When system resumes, any time out value (if we set using KMDF time out value) might be expires.
3844  // This will cause the waiting request being failed (behavior change). We’d rather not set time out value.
3845 
3846  _Analysis_assume_(options.Timeout != 0);
3847  requestSent = WdfRequestSend(Request, IoTarget, &options);
3848  _Analysis_assume_(options.Timeout == 0);
3849 
3850  // If WdfRequestSend fails, or if the WDF_REQUEST_SEND_OPTION_SYNCHRONOUS flag is set,
3851  // the driver can call WdfRequestGetStatus immediately after calling WdfRequestSend.
3852  if ((requestSent == FALSE) ||
3854  {
3855  status = WdfRequestGetStatus(Request);
3856 
3857  if (requestSent == FALSE)
3858  {
3859  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL,
3860  "WdfRequestSend failed: %lx\n",
3861  status
3862  ));
3863  }
3864  }
3865  else
3866  {
3868  }
3869 
3870  if (RequestSent != NULL)
3871  {
3872  *RequestSent = requestSent;
3873  }
3874  }
3875 
3876  return status;
3877 }
3878 
LARGE_INTEGER TimeSentDownLasttTime
Definition: cdrom.h:637
#define IOCTL_SCSI_EXECUTE_OUT
Definition: cdrw_hw.h:1452
_IRQL_requires_max_(PASSIVE_LEVEL)
Definition: common.c:135
#define CLASS_ERROR_LEVEL_1
Definition: cdromp.h:130
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
signed char * PCHAR
Definition: retypes.h:7
struct _FOUR_BYTE * PFOUR_BYTE
FORCEINLINE VOID WDF_REQUEST_SEND_OPTIONS_INIT(_Out_ PWDF_REQUEST_SEND_OPTIONS Options, _In_ ULONG Flags)
Definition: wdfrequest.h:409
#define SRB_FUNCTION_UNLOCK_QUEUE
Definition: srb.h:325
#define STATUS_DEVICE_DOES_NOT_EXIST
Definition: ntstatus.h:428
_In_ WDFREQUEST _In_ BOOLEAN RequestFormated
Definition: cdrom.h:1246
#define CDROM_READ_CAPACITY_TIMEOUT
Definition: cdrom.h:130
_Must_inspect_result_ _In_ WDFDEVICE _In_ DEVICE_REGISTRY_PROPERTY _In_ ULONG BufferLength
Definition: wdfdevice.h:3767
#define max(a, b)
Definition: svc.c:63
#define _In_opt_z_
Definition: no_sal2.h:218
#define KeRaiseIrql(irql, oldIrql)
Definition: env_spec_w32.h:597
enum _STORAGE_PROPERTY_ID STORAGE_PROPERTY_ID
BOOLEAN ReleaseQueueInProgress
Definition: cdrom.h:581
* PSTORAGE_DESCRIPTOR_HEADER
Definition: ntddstor.h:560
#define SCSIOP_SYNCHRONIZE_CACHE
Definition: cdrw_hw.h:918
FORCEINLINE VOID ScratchBuffer_EndUse(_Inout_ PCDROM_DEVICE_EXTENSION DeviceExtension)
Definition: scratch.h:104
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
#define KeLowerIrql(oldIrql)
Definition: env_spec_w32.h:602
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
#define SRB_FUNCTION_QUIESCE_DEVICE
Definition: srb.h:90
ULONG SrbFlags
Definition: srb.h:252
_In_ size_t _In_ UCHAR PageMode
Definition: cdrom.h:1325
VOID RequestCompletion(_In_ PCDROM_DEVICE_EXTENSION DeviceExtension, _In_ WDFREQUEST Request, _In_ NTSTATUS Status, _In_ ULONG_PTR Information)
Definition: common.c:3439
VOID DeviceSetMediaChangeStateEx(_In_ PCDROM_DEVICE_EXTENSION DeviceExtension, _In_ MEDIA_CHANGE_DETECTION_STATE NewState, _Inout_opt_ PMEDIA_CHANGE_DETECTION_STATE OldState)
Definition: autorun.c:751
VOID DevicePerfIncrementErrorCount(_In_ PCDROM_DEVICE_EXTENSION DeviceExtension)
Definition: common.c:1378
PVOID OriginalRequest
Definition: srb.h:258
UCHAR Cdb[16]
Definition: srb.h:271
_In_ WDFIOTARGET _In_ PWDF_REQUEST_COMPLETION_PARAMS Params
Definition: wdfrequest.h:306
#define _In_reads_bytes_(s)
Definition: no_sal2.h:170
struct _MODE_DISCONNECT_PAGE * PMODE_DISCONNECT_PAGE
NTSTATUS RequestDuidGetDeviceIdProperty(_In_ PCDROM_DEVICE_EXTENSION DeviceExtension, _In_ WDFREQUEST Request, _In_ WDF_REQUEST_PARAMETERS RequestParameters, _Out_ size_t *DataLength)
Definition: common.c:2797
GLuint64EXT * result
Definition: glext.h:11304
struct _CDB::_MEDIA_REMOVAL MEDIA_REMOVAL
BOOLEAN WriteAllowed
Definition: cdrom.h:250
#define STATUS_MORE_PROCESSING_REQUIRED
Definition: shellext.h:68
Definition: http.c:7251
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
_In_ const GUID _In_ ULONG ExtraDataSize
Definition: classpnp.h:1429
#define PLUGPLAY_REGKEY_DEVICE
Definition: iofuncs.h:2782
PCDROM_PRIVATE_FDO_DATA PrivateFdoData
Definition: cdrom.h:605
#define SRB_FLAGS_NO_QUEUE_FREEZE
Definition: srb.h:396
#define KEY_READ
Definition: nt_native.h:1023
#define TRUE
Definition: types.h:120
#define SCSIOP_MODE_SENSE
Definition: cdrw_hw.h:896
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
uint16_t * PWSTR
Definition: typedefs.h:56
CDROM_DATA DeviceAdditionalData
Definition: cdrom.h:598
WDFIOTARGET IoTarget
Definition: cdrom.h:476
unsigned char * PUCHAR
Definition: retypes.h:3
#define IoIsErrorUserInduced(Status)
Definition: iofuncs.h:2813
Definition: cdrw_hw.h:28
LONG NTSTATUS
Definition: precomp.h:26
BOOLEAN SyncRequired
Definition: cdrom.h:643
UCHAR PreferredDriveRegionCode
Definition: ntddcdvd.h:232
struct _CDB::_SYNCHRONIZE_CACHE10 SYNCHRONIZE_CACHE10
struct _FEATURE_HEADER * PFEATURE_HEADER
WDF_REQUEST_TYPE Type
Definition: wdfrequest.h:142
#define REVERSE_BYTES(Destination, Source)
Definition: scsi.h:3465
#define DO_VERIFY_VOLUME
Definition: env_spec_w32.h:393
GLdouble GLdouble t
Definition: gl.h:2047
#define STATUS_INVALID_DEVICE_REQUEST
Definition: udferr_usr.h:138
#define InterlockedCompareExchange
Definition: interlocked.h:104
IN PVOID IN PVOID IN USHORT IN USHORT Size
Definition: pci.h:361
_In_ ULONG const _In_ FEATURE_NUMBER const Feature
Definition: cdrom.h:1075
UCHAR CdbLength
Definition: srb.h:250
#define SRB_FUNCTION_FLUSH_QUEUE
Definition: srb.h:321
GLuint buffer
Definition: glext.h:5915
_In_ WDFREQUEST Request
Definition: wdfdevice.h:547
#define DVD_TAG_DVD_REGION
Definition: cdrom.h:749
ULONG LogicalBlockAddress
Definition: cdrw_hw.h:1471
VOID NTAPI MmUnlockPages(IN PMDL Mdl)
Definition: mdlsup.c:1439
ULONG BytesPerSector
Definition: ntdddisk.h:409
LARGE_INTEGER TimeReceived
Definition: cdrom.h:635
ULONG TracksPerCylinder
Definition: ntdddisk.h:407
VOID DeviceSendNotification(_In_ PCDROM_DEVICE_EXTENSION DeviceExtension, _In_ const GUID *Guid, _In_ ULONG ExtraDataSize, _In_opt_ PVOID ExtraData)
Definition: common.c:799
struct _CDB::_CDB10 CDB10
if(dx==0 &&dy==0)
Definition: linetemp.h:174
#define SRB_FLAGS_DATA_IN
Definition: srb.h:392
#define TRACE_LEVEL_INFORMATION
Definition: storswtr.h:29
ULONG TimeOutValue
Definition: srb.h:254
ULONG PickDvdRegion
Definition: cdrom.h:354
_In_ WDFREQUEST _In_ NTSTATUS _In_ ULONG_PTR Information
Definition: wdfrequest.h:1044
#define SRB_STATUS(Status)
Definition: srb.h:381
PSYNC_HANDLER SyncCallback
Definition: cdrom.h:645
#define SENSE_BUFFER_SIZE
Definition: cdrw_hw.h:1183
#define WHICH_BIT(Data, Bit)
Definition: tools.h:80
struct _COMPLETION_CONTEXT * PCOMPLETION_CONTEXT
#define STATUS_INVALID_HANDLE
Definition: ntstatus.h:245
#define _In_opt_
Definition: no_sal2.h:212
struct _FEATURE_DATA_FIRMWARE_DATE * PFEATURE_DATA_FIRMWARE_DATE
_SEH2_TRY
Definition: create.c:4226
#define WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(_attributes, _contexttype)
Definition: wdfobject.h:170
GLint limit
Definition: glext.h:10326
#define IoSetCompletionRoutine(_Irp, _CompletionRoutine, _Context, _InvokeOnSuccess, _InvokeOnError, _InvokeOnCancel)
Definition: irp.cpp:498
FORCEINLINE WDFDRIVER WdfGetDriver(VOID)
Definition: wdfdriver.h:194
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define STATUS_INVALID_DEVICE_STATE
Definition: udferr_usr.h:178
#define IRP_MJ_SCSI
struct _DVD_COPYRIGHT_DESCRIPTOR * PDVD_COPYRIGHT_DESCRIPTOR
VOID RequestClearSendTime(_In_ WDFREQUEST Request)
Definition: common.c:111
NTSTATUS NTAPI RequestAsynchronousIrpCompletion(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, _In_reads_opt_(_Inexpressible_("varies")) PVOID Context)
Definition: common.c:1082
WDFMEMORY ReleaseQueueInputMemory
Definition: cdrom.h:579
#define STATUS_INTERNAL_ERROR
Definition: ntstatus.h:465
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define MAXIMUM_RETRIES
Definition: cdrom.h:124
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2055
return STATUS_NOT_IMPLEMENTED
GLenum GLint GLuint mask
Definition: glext.h:6028
_In_ ULONG _In_ UCHAR _In_ UCHAR PageControl
Definition: cdrom.h:1316
#define ScratchBuffer_BeginUse(context)
Definition: scratch.h:87
* 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
#define SCSI_CDROM_TIMEOUT
Definition: cdrom.c:170
struct _DVD_RPC_KEY * PDVD_RPC_KEY
#define FALSE
Definition: types.h:117
GLenum const GLfloat * params
Definition: glext.h:5645
_In_ PIRP Irp
Definition: csq.h:116
#define TRACE_LEVEL_VERBOSE
Definition: storswtr.h:30
VOID DeviceSendIoctlAsynchronously(_In_ PCDROM_DEVICE_EXTENSION DeviceExtension, _In_ ULONG IoControlCode, _In_ PDEVICE_OBJECT TargetDeviceObject)
Definition: common.c:1030
#define FREE_POOL(_PoolPtr)
Definition: cdrom.h:782
long LONG
Definition: pedump.c:60
Definition: devices.h:37
#define SCSIOP_SET_STREAMING
Definition: cdrw_hw.h:963
UCHAR BlockDescriptorLength[2]
Definition: cdrw_hw.h:2516
WDFREQUEST ReleaseQueueRequest
Definition: cdrom.h:577
GLenum GLuint GLenum GLsizei length
Definition: glext.h:5579
NTSTATUS NTAPI KeDelayExecutionThread(IN KPROCESSOR_MODE WaitMode, IN BOOLEAN Alertable, IN PLARGE_INTEGER Interval OPTIONAL)
Definition: wait.c:283
UCHAR UserResetsAvailable
Definition: scsi.h:2923
VOID NTAPI RequestDummyCompletionRoutine(_In_ WDFREQUEST Request, _In_ WDFIOTARGET Target, _In_ PWDF_REQUEST_COMPLETION_PARAMS Params, _In_ WDFCONTEXT Context)
Definition: common.c:3520
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
#define SRB_FLAGS_BYPASS_LOCKED_QUEUE
Definition: srb.h:402
FORCEINLINE VOID WDF_REQUEST_REUSE_PARAMS_INIT(_Out_ PWDF_REQUEST_REUSE_PARAMS Params, _In_ ULONG Flags, _In_ NTSTATUS Status)
Definition: wdfrequest.h:364
#define SRB_STATUS_PENDING
Definition: srb.h:332
unsigned char BOOLEAN
MEDIA_LOCK_TYPE
Definition: cdromp.h:288
_In_z_ PCHAR TargetString
Definition: cdrom.h:954
WDFFILEOBJECT ExclusiveOwner
Definition: cdrom.h:373
#define DVD_DEFAULT_REGION
Definition: cdrom.h:760
union _CDB * PCDB
#define _Out_
Definition: no_sal2.h:160
#define CLEAR_FLAG(Flags, Bit)
Definition: cdrom.h:1494
struct _MODE_PARAMETER_HEADER10 MODE_PARAMETER_HEADER10
EVT_WDF_REQUEST_COMPLETION_ROUTINE * PFN_WDF_REQUEST_COMPLETION_ROUTINE
Definition: wdfrequest.h:313
_In_ ULONG _In_opt_ WDFREQUEST _In_opt_ PVOID _In_ size_t _In_ PVOID _In_ size_t _Out_ size_t * DataLength
Definition: cdrom.h:1437
Definition: bufpool.h:45
struct _MODE_PARAMETER_HEADER * PMODE_PARAMETER_HEADER
_In_ ULONG _In_ UCHAR PageCode
Definition: cdrom.h:1316
struct _CDB::_START_STOP START_STOP
const char * LPCSTR
Definition: xmlstorage.h:183
VOID NTAPI DeviceReleaseQueueCompletion(_In_ WDFREQUEST Request, _In_ WDFIOTARGET Target, _In_ PWDF_REQUEST_COMPLETION_PARAMS Params, _In_ WDFCONTEXT Context)
Definition: common.c:1257
int options
Definition: main.c:106
VOID NTAPI KeQueryTickCount(IN PLARGE_INTEGER TickCount)
Definition: clock.c:165
enum _MEDIA_CHANGE_DETECTION_STATE MEDIA_CHANGE_DETECTION_STATE
_In_ WDFREQUEST _In_ WDFFILEOBJECT FileObject
Definition: wdfdevice.h:547
#define TEST_FLAG(Flags, Bit)
Definition: cdrom.h:1495
struct _CDB::_MODE_SENSE MODE_SENSE
SYNC_HANDLER * PSYNC_HANDLER
Definition: cdrom.h:628
int min(int a, int b)
Definition: common.c:179
_In_ ULONG const Usable
Definition: cdrom.h:1084
Status
Definition: gdiplustypes.h:24
#define CDROM_TAG_COMPLETION_CONTEXT
Definition: cdrom.h:729
#define KEY_WRITE
Definition: nt_native.h:1031
int64_t LONGLONG
Definition: typedefs.h:68
#define _Out_opt_
Definition: no_sal2.h:214
VOID RequestSetupMcnSyncIrp(_In_ PCDROM_DEVICE_EXTENSION DeviceExtension)
Definition: autorun.c:2749
#define STATUS_NOT_FOUND
Definition: shellext.h:72
VOID DeviceReleaseQueue(_In_ WDFDEVICE Device)
Definition: common.c:1179
#define InterlockedExchangePointer(Target, Value)
Definition: dshow.h:45
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
#define _SEH2_YIELD(STMT_)
Definition: pseh2_64.h:8
union _WDF_REQUEST_PARAMETERS::@3665 Parameters
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define STATUS_PENDING
Definition: ntstatus.h:82
PZERO_POWER_ODD_INFO ZeroPowerODDInfo
Definition: cdrom.h:566
_Must_inspect_result_ _In_ WDFOBJECT _In_ CONST GUID * Guid
Definition: wdfobject.h:760
VOID NTAPI DeviceRestoreDefaultSpeed(_In_ WDFWORKITEM WorkItem)
Definition: common.c:2631
GLintptr offset
Definition: glext.h:5920
static void Exit(void)
Definition: sock.c:1331
LARGE_INTEGER Cylinders
Definition: ntdddisk.h:405
UCHAR Function
Definition: srb.h:242
LPCSTR LockTypeStrings[]
Definition: common.c:58
ULONG SectorsPerTrack
Definition: ntdddisk.h:408
#define DECLARE_CONST_UNICODE_STRING(_variablename, _string)
Definition: wdfcore.h:161
#define KeAcquireSpinLock(sl, irql)
Definition: env_spec_w32.h:609
_In_ WDFFILEOBJECT _In_ BOOLEAN IgnorePreviousMediaChanges
Definition: cdrom.h:1225
#define STATUS_CANCELLED
Definition: udferr_usr.h:170
int strncmp(const char *String1, const char *String2, ACPI_SIZE Count)
Definition: utclib.c:534
PFIXED_SENSE_DATA senseInfoBuffer
Definition: scsi.h:3710
struct _MODE_PARAMETER_HEADER10 * PMODE_PARAMETER_HEADER10
#define SRB_FLAGS_DISABLE_SYNCH_TRANSFER
Definition: srb.h:389
_In_ WDFREQUEST _In_ MEDIA_LOCK_TYPE LockType
Definition: cdrom.h:1334
MEDIA_TYPE MediaType
Definition: ntdddisk.h:406
_In_ PREAD_CAPACITY_DATA ReadCapacityBuffer
Definition: cdrom.h:1103
#define RTL_SIZEOF_THROUGH_FIELD(type, field)
Definition: ntbasedef.h:672
#define EXCLUSIVE_MODE(_CdData)
Definition: cdrom.h:788
USHORT Length
Definition: srb.h:241
struct _STORAGE_DEVICE_UNIQUE_IDENTIFIER * PSTORAGE_DEVICE_UNIQUE_IDENTIFIER
#define _Inout_
Definition: no_sal2.h:162
struct _SCSI_REQUEST_BLOCK SCSI_REQUEST_BLOCK
struct _PERFORMANCE_DESCRIPTOR PERFORMANCE_DESCRIPTOR
VOID NTAPI IoFreeMdl(PMDL Mdl)
Definition: iomdl.c:146
#define DVD_SET_RPC_KEY_LENGTH
Definition: cdrw_usr.h:1598
#define _In_reads_opt_(s)
Definition: no_sal2.h:222
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
#define CDROM_TAG_SYNC_EVENT
Definition: cdrom.h:732
#define SRB_FLAGS_DISABLE_DISCONNECT
Definition: srb.h:388
DVD_KEY_TYPE KeyType
Definition: ntddcdvd.h:178
struct _FEATURE_HEADER FEATURE_HEADER
unsigned char UCHAR
Definition: xmlstorage.h:181
#define SRB_FLAGS_NO_DATA_TRANSFER
Definition: srb.h:394
#define EXCLUSIVE_OWNER(_CdData, _FileObject)
Definition: cdrom.h:789
char * PBOOLEAN
Definition: retypes.h:11
NTSTATUS RequestDuidGetDeviceProperty(_In_ PCDROM_DEVICE_EXTENSION DeviceExtension, _In_ WDFREQUEST Request, _In_ WDF_REQUEST_PARAMETERS RequestParameters, _Out_ size_t *DataLength)
Definition: common.c:2888
BOOLEAN RequestSenseInfoInterpret(_In_ PCDROM_DEVICE_EXTENSION DeviceExtension, _In_ WDFREQUEST Request, _In_ PSCSI_REQUEST_BLOCK Srb, _In_ ULONG RetriedCount, _Out_ NTSTATUS *Status, _Out_opt_ _Deref_out_range_(0, MAXIMUM_RETRY_FOR_SINGLE_IO_IN_100NS_UNITS) LONGLONG *RetryIntervalIn100ns)
Definition: sense.c:2467
#define SRB_STATUS_QUEUE_FROZEN
Definition: srb.h:378
FORCEINLINE VOID FREE_PORT_ALLOCATED_SENSE_BUFFER(_In_ PCDROM_DEVICE_EXTENSION DeviceExtension, _In_ PSCSI_REQUEST_BLOCK Srb)
Definition: cdrom.h:839
NTSTATUS RequestSend(_In_ PCDROM_DEVICE_EXTENSION DeviceExtension, _In_ WDFREQUEST Request, _In_ WDFIOTARGET IoTarget, _In_ ULONG Flags, _Out_opt_ PBOOLEAN RequestSent)
Definition: common.c:3793
#define SCSIOP_MEDIUM_REMOVAL
Definition: cdrw_hw.h:902
#define VOID
Definition: acefi.h:82
_In_opt_ PWSTR _In_ PWSTR ParameterName
Definition: cdrom.h:960
_In_ WDFREQUEST _In_ size_t _In_ size_t _In_ ULONG IoControlCode
Definition: wdfio.h:318
#define PLUGPLAY_REGKEY_DRIVER
Definition: usbd.c:42
VOID RequestSetSentTime(_In_ WDFREQUEST Request)
Definition: common.c:79
UCHAR RegionMask
Definition: scsi.h:2926
FORCEINLINE BOOLEAN PORT_ALLOCATED_SENSE(_In_ PCDROM_DEVICE_EXTENSION DeviceExtension, _In_ PSCSI_REQUEST_BLOCK Srb)
Definition: cdrom.h:826
#define IOCTL_DVD_READ_KEY
Definition: cdrw_usr.h:160
#define PASSIVE_LEVEL
Definition: env_spec_w32.h:693
_Must_inspect_result_ _In_ WDFDEVICE Device
Definition: wdfchildlist.h:474
__drv_aliasesMem FORCEINLINE PIO_STACK_LOCATION IoGetNextIrpStackLocation(_In_ PIRP Irp)
Definition: iofuncs.h:2691
_Must_inspect_result_ FORCEINLINE BOOLEAN WdfRequestSend(_In_ WDFREQUEST Request, _In_ WDFIOTARGET Target, _In_opt_ PWDF_REQUEST_SEND_OPTIONS Options)
Definition: wdfrequest.h:677
_In_ PSCSI_REQUEST_BLOCK _In_opt_ PVOID _In_ ULONG _In_ BOOLEAN _In_opt_ WDFREQUEST OriginalRequest
Definition: cdrom.h:989
WDFSPINLOCK ReleaseQueueSpinLock
Definition: cdrom.h:576
ACPI_PHYSICAL_ADDRESS ACPI_SIZE BOOLEAN Warn BOOLEAN Physical UINT32 ACPI_TABLE_HEADER *OutTableHeader ACPI_TABLE_HEADER **OutTable ACPI_HANDLE UINT32 ACPI_WALK_CALLBACK ACPI_WALK_CALLBACK void void **ReturnValue UINT32 ACPI_BUFFER *RetPathPtr ACPI_OBJECT_HANDLER Handler
Definition: acpixf.h:668
KSPIN_LOCK SpinLock
Definition: cdromp.h:351
#define IOCTL_SCSI_EXECUTE_IN
Definition: cdrw_hw.h:1451
#define InterlockedExchange
Definition: armddk.h:54
struct _WDF_REQUEST_PARAMETERS::@3665::@3669 DeviceIoControl
enum _FEATURE_NUMBER FEATURE_NUMBER
struct _CDB::_SET_STREAMING SET_STREAMING
#define TRACE_LEVEL_ERROR
Definition: storswtr.h:27
#define TRACE_LEVEL_WARNING
Definition: storswtr.h:28
#define DVD_MAX_REGION
Definition: cdrom.h:761
_In_ PSCSI_REQUEST_BLOCK _In_opt_ PVOID _In_ ULONG _In_ BOOLEAN WriteToDevice
Definition: cdrom.h:989
PMDL NTAPI IoAllocateMdl(IN PVOID VirtualAddress, IN ULONG Length, IN BOOLEAN SecondaryBuffer, IN BOOLEAN ChargeQuota, IN PIRP Irp)
Definition: iomdl.c:22
struct _WDF_REQUEST_PARAMETERS::@3665::@3667 Read
#define IOCTL_SCSI_EXECUTE_NONE
Definition: cdrw_hw.h:1453
#define CDROM_TAG_STREAM
Definition: cdrom.h:738
VOID RequestSetReceivedTime(_In_ WDFREQUEST Request)
Definition: common.c:64
struct _CDROM_PRIVATE_FDO_DATA::@1018 Perf
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
#define _In_
Definition: no_sal2.h:158
_In_opt_ WDFREQUEST _In_opt_ PWDF_REQUEST_PARAMETERS RequestParameters
Definition: ioctl.h:137
FORCEINLINE VOID WDF_OBJECT_ATTRIBUTES_INIT(_Out_ PWDF_OBJECT_ATTRIBUTES Attributes)
Definition: wdfobject.h:147
NTSTATUS RequestSetContextFields(_In_ WDFREQUEST Request, _In_ PSYNC_HANDLER Handler)
Definition: common.c:2748
LARGE_INTEGER PartitionLength
Definition: cdrom.h:530
_SEH2_END
Definition: create.c:4400
#define InterlockedIncrement
Definition: armddk.h:53
DISK_GEOMETRY DiskGeometry
Definition: cdrom.h:524
#define STATUS_BUFFER_OVERFLOW
Definition: shellext.h:66
VOID NTAPI MmProbeAndLockPages(IN PMDL Mdl, IN KPROCESSOR_MODE AccessMode, IN LOCK_OPERATION Operation)
Definition: mdlsup.c:935
unsigned short USHORT
Definition: pedump.c:61
static calc_node_t temp
Definition: rpn_ieee.c:38
#define _In_z_
Definition: no_sal2.h:164
__u16 date
Definition: mkdosfs.c:366
VOID NTAPI DeviceAsynchronousCompletion(_In_ WDFREQUEST Request, _In_ WDFIOTARGET Target, _In_ PWDF_REQUEST_COMPLETION_PARAMS Params, _In_ WDFCONTEXT Context)
Definition: common.c:1116
CDROM_DEVICE_INTERFACES
Definition: cdrom.h:767
_In_ WDFREQUEST _In_opt_ PFN_WDF_REQUEST_COMPLETION_ROUTINE CompletionRoutine
Definition: wdfrequest.h:893
struct _DVD_COPY_PROTECT_KEY * PDVD_COPY_PROTECT_KEY
struct _DVD_SET_RPC_KEY * PDVD_SET_RPC_KEY
#define REVERSE_BYTES_SHORT(Destination, Source)
Definition: scsi.h:3474
#define _Analysis_assume_
Definition: no_sal2.h:388
WDFOBJECT ParentObject
Definition: wdfobject.h:130
#define SRB_SIMPLE_TAG_REQUEST
Definition: srb.h:415
unsigned int * PULONG
Definition: retypes.h:1
BOOLEAN ReleaseQueueNeeded
Definition: cdrom.h:580
#define SRB_FLAGS_DATA_OUT
Definition: srb.h:393
_In_opt_ PWSTR _In_ PWSTR _Inout_ PULONG ParameterValue
Definition: cdrom.h:960
#define NULL
Definition: types.h:112
NTSTATUS NTAPI IoCallDriver(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
Definition: irp.c:1218
FORCEINLINE BOOLEAN IsVolumeMounted(_In_ PDEVICE_OBJECT DeviceObject)
Definition: cdrom.h:1514
#define KeReleaseSpinLock(sl, irql)
Definition: env_spec_w32.h:627
#define IOCTL_MCN_SYNC_FAKE_IOCTL
Definition: cdrom.h:181
_In_opt_ PWSTR SubkeyName
Definition: cdrom.h:960
#define WDF_NO_OBJECT_ATTRIBUTES
Definition: wdftypes.h:105
#define START_UNIT_TIMEOUT
Definition: cdrom.h:132
FORCEINLINE VOID WDF_REQUEST_PARAMETERS_INIT(_Out_ PWDF_REQUEST_PARAMETERS Parameters)
Definition: wdfrequest.h:211
_In_ WDFIOTARGET Target
Definition: wdfrequest.h:306
Definition: tftpd.h:85
#define SCSIOP_READ_CAPACITY
Definition: cdrw_hw.h:904
#define CdromMmcUpdateRequired
Definition: cdrom.h:242
LARGE_INTEGER TimeSentDownFirstTime
Definition: cdrom.h:636
CDROM_MMC_EXTENSION Mmc
Definition: cdrom.h:341
SCSI_REQUEST_BLOCK ReleaseQueueSrb
Definition: cdrom.h:578
VOID DeviceSendStartUnit(_In_ WDFDEVICE Device)
Definition: common.c:877
struct tagContext Context
Definition: acpixf.h:1034
VOID NTAPI IoFreeIrp(IN PIRP Irp)
Definition: irp.c:1666
DVD_STRUCTURE_FORMAT Format
Definition: ntddcdvd.h:120
_Must_inspect_result_ _In_opt_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFWAITLOCK * Lock
Definition: wdfsync.h:124
#define SRB_FUNCTION_EXECUTE_SCSI
Definition: srb.h:307
unsigned int ULONG
Definition: retypes.h:1
_Must_inspect_result_ _In_ WDFDEVICE _In_opt_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFIOTARGET * IoTarget
Definition: wdfiotarget.h:363
#define DVD_RPC_KEY_LENGTH
Definition: cdrw_usr.h:1597
#define CDROM_TAG_NOTIFICATION
Definition: cdrom.h:739
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define SRB_STATUS_SUCCESS
Definition: srb.h:333
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
VOID NTAPI IoSetHardErrorOrVerifyDevice(IN PIRP Irp, IN PDEVICE_OBJECT DeviceObject)
Definition: util.c:316
PIRP NTAPI IoAllocateIrp(IN CCHAR StackSize, IN BOOLEAN ChargeQuota)
Definition: irp.c:615
#define CDROM_TAG_SENSE_INFO
Definition: cdrom.h:735
static char * dest
Definition: rtl.c:135
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:6
const char * PCSTR
Definition: typedefs.h:52
#define STATUS_SUCCESS
Definition: shellext.h:65
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:12
_Must_inspect_result_ _In_ PWDF_WORKITEM_CONFIG _In_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFWORKITEM * WorkItem
Definition: wdfworkitem.h:110
IN PSCSI_REQUEST_BLOCK Srb
Definition: class2.h:49
#define SRB_FLAGS_D3_PROCESSING
Definition: srb.h:156
BOOLEAN LoggedTURFailureSinceLastIO
Definition: cdromp.h:346
struct _NAMED_PIPE_CREATE_PARAMETERS * Parameters
Definition: iotypes.h:3127
IN OUT PVCB IN PDEVICE_OBJECT TargetDeviceObject
Definition: fatprocs.h:1673
* PSTORAGE_DEVICE_ID_DESCRIPTOR
Definition: ntddstor.h:742
NTSTATUS NTAPI IoReportTargetDeviceChangeAsynchronous(IN PDEVICE_OBJECT PhysicalDeviceObject, IN PVOID NotificationStructure, IN PDEVICE_CHANGE_COMPLETE_CALLBACK Callback OPTIONAL, IN PVOID Context OPTIONAL)
Definition: pnpreport.c:460
BOOLEAN MonitorStartStopUnit
Definition: cdromp.h:274
signed int * PLONG
Definition: retypes.h:5
static SERVICE_STATUS status
Definition: service.c:31
#define APC_LEVEL
Definition: env_spec_w32.h:695
#define CLASS_ERROR_LEVEL_2
Definition: cdromp.h:131
struct CFHEADER header
Definition: fdi.c:101
#define SET_FLAG(Flags, Bit)
Definition: cdrom.h:1493
#define SCSIOP_START_STOP_UNIT
Definition: cdrw_hw.h:897
FxIrp * irp
_Must_inspect_result_ _In_ WDFDEVICE _In_ LPCGUID InterfaceType
Definition: wdffdo.h:461
#define SRB_FUNCTION_LOCK_QUEUE
Definition: srb.h:324
#define SRB_FLAGS_QUEUE_ACTION_ENABLE
Definition: srb.h:387
struct _WDF_REQUEST_PARAMETERS::@3665::@3668 Write
LONGLONG QuadPart
Definition: typedefs.h:114
struct DVD_READ_STRUCTURE * PDVD_READ_STRUCTURE
WDFREQUEST OriginalRequest
Definition: cdrom.h:633
_In_ PSCSI_REQUEST_BLOCK _In_opt_ PVOID BufferAddress
Definition: cdrom.h:989
#define IRP_MJ_DEVICE_CONTROL
Definition: rdpdr.c:52
_Must_inspect_result_ FORCEINLINE NTSTATUS WdfWaitLockAcquire(_In_ _Requires_lock_not_held_(_Curr_) WDFWAITLOCK Lock, _In_opt_ PLONGLONG Timeout)
Definition: wdfsync.h:173
#define PAGED_CODE()
GUID * LPGUID
Definition: guiddef.h:81
#define NT_ASSERT
Definition: rtlfuncs.h:3312
Definition: ps.c:97