ReactOS  0.4.15-dev-3324-gda4e15f
autorun.c
Go to the documentation of this file.
1 /*++
2 
3 Copyright (C) Microsoft Corporation. All rights reserved.
4 
5 Module Name:
6 
7  autorun.c
8 
9 Abstract:
10 
11  Code for support of media change detection in the cd/dvd driver
12 
13 Environment:
14 
15  kernel mode only
16 
17 Notes:
18 
19 
20 Revision History:
21 
22 --*/
23 
24 #include "stddef.h"
25 #include "string.h"
26 
27 #include "ntddk.h"
28 #include "ntddstor.h"
29 #include "cdrom.h"
30 #include "mmc.h"
31 #include "ioctl.h"
32 
33 #include "ntstrsafe.h"
34 
35 #ifdef DEBUG_USE_WPP
36 #include "autorun.tmh"
37 #endif
38 
39 #define GESN_TIMEOUT_VALUE (0x4)
40 #define GESN_BUFFER_SIZE (0x8)
41 #define GESN_DEVICE_BUSY_LOWER_THRESHOLD_100_MS (2)
42 
43 #define MAXIMUM_IMMEDIATE_MCN_RETRIES (0x20)
44 #define MCN_REG_SUBKEY_NAME (L"MediaChangeNotification")
45 #define MCN_REG_AUTORUN_DISABLE_INSTANCE_NAME (L"AlwaysDisableMCN")
46 #define MCN_REG_AUTORUN_ENABLE_INSTANCE_NAME (L"AlwaysEnableMCN")
47 
48 //
49 // Only send polling irp when device is fully powered up and a
50 // power down irp is not in progress.
51 //
52 // NOTE: This helps close a window in time where a polling irp could cause
53 // a drive to spin up right after it has powered down. The problem is
54 // that SCSIPORT, ATAPI and SBP2 will be in the process of powering
55 // down (which may take a few seconds), but won't know that. It would
56 // then get a polling irp which will be put into its queue since it
57 // the disk isn't powered down yet. Once the disk is powered down it
58 // will find the polling irp in the queue and then power up the
59 // device to do the poll. They do not want to check if the polling
60 // irp has the SRB_NO_KEEP_AWAKE flag here since it is in a critical
61 // path and would slow down all I/Os. A better way to fix this
62 // would be to serialize the polling and power down irps so that
63 // only one of them is sent to the device at a time.
64 //
65 
67 BOOLEAN
68 DeviceIsMediaChangeDisabledDueToHardwareLimitation(
69  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
70  );
71 
73 BOOLEAN
74 DeviceIsMediaChangeDisabledForClass(
75  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
76  );
77 
80 DeviceMediaChangeDeviceInstanceOverride(
81  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
83  );
84 
87 DeviceInitializeMcn(
88  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
90  );
91 
94 DeviceInitializeGesn(
95  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
96  );
97 
100 GesnDataInterpret(
101  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
103  _Out_ PBOOLEAN ResendImmediately
104  );
105 
106 RTL_QUERY_REGISTRY_ROUTINE DeviceMediaChangeRegistryCallBack;
107 
108 EVT_WDF_WORKITEM DeviceDisableGesn;
109 
110 #if ALLOC_PRAGMA
111 
112 #pragma alloc_text(PAGE, DeviceInitializeMediaChangeDetection)
113 #pragma alloc_text(PAGE, DeviceEnableMediaChangeDetection)
114 #pragma alloc_text(PAGE, DeviceDisableMediaChangeDetection)
115 #pragma alloc_text(PAGE, DeviceSendDelayedMediaChangeNotifications)
116 #pragma alloc_text(PAGE, DeviceReleaseMcnResources)
117 #pragma alloc_text(PAGE, DeviceMediaChangeRegistryCallBack)
118 #pragma alloc_text(PAGE, DeviceInitializeMcn)
119 #pragma alloc_text(PAGE, DeviceDisableGesn)
120 
121 #pragma alloc_text(PAGE, DeviceIsMediaChangeDisabledDueToHardwareLimitation)
122 #pragma alloc_text(PAGE, DeviceMediaChangeDeviceInstanceOverride)
123 #pragma alloc_text(PAGE, DeviceIsMediaChangeDisabledForClass)
124 
125 #pragma alloc_text(PAGE, DeviceDisableMainTimer)
126 
127 #pragma alloc_text(PAGE, GesnDataInterpret)
128 
129 #pragma alloc_text(PAGE, RequestSetupMcnRequest)
130 #pragma alloc_text(PAGE, RequestPostWorkMcnRequest)
131 #pragma alloc_text(PAGE, RequestSendMcnRequest)
132 
133 //
134 // DeviceEnableMainTimer is called by EvtDeviceD0Entry which can't be made pageable
135 // so neither is DeviceEnableMainTimer
136 //
137 //#pragma alloc_text(PAGE, DeviceEnableMainTimer)
138 
139 #pragma alloc_text(PAGE, DeviceInitializeGesn)
140 
141 #pragma alloc_text(PAGE, RequestHandleMcnControl)
142 
143 #endif
144 
145 #pragma warning(push)
146 #pragma warning(disable:4152) // nonstandard extension, function/data pointer conversion in expression
147 
148 
150 NTSTATUS
151 GesnDataInterpret(
152  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
154  _Out_ PBOOLEAN ResendImmediately
155  )
156 /*++
157 
158 Routine Description:
159 
160  This routine will interpret the data returned for a GESN command, and
161  (if appropriate) set the media change event, and broadcast the
162  appropriate events to user mode for applications who care.
163 
164 Arguments:
165 
166  DeviceExtension - the device extension
167 
168  Header - the resulting data from a GESN event.
169  requires at least EIGHT valid bytes (header == 4, data == 4)
170 
171  ResendImmediately - whether or not to immediately resend the request.
172  this should be FALSE if there was no event, FALSE if the reported
173  event was of the DEVICE BUSY class, else true.
174 
175 Return Value:
176 
177  STATUS_SUCCESS if successful, an error code otherwise
178 
179 Notes:
180 
181  DataBuffer must be at least four bytes of valid data (header == 4 bytes),
182  and have at least eight bytes of allocated memory (all events == 4 bytes).
183 
184  The call to StartNextPacket may occur before this routine is completed.
185  the operational change notifications are informational in nature, and
186  while useful, are not neccessary to ensure proper operation. For example,
187  if the device morphs to no longer supporting WRITE commands, all further
188  write commands will fail. There exists a small timing window wherein
189  IOCTL_IS_DISK_WRITABLE may be called and get an incorrect response. If
190  a device supports software write protect, it is expected that the
191  application can handle such a case.
192 
193  NOTE: perhaps setting the updaterequired byte to one should be done here.
194  if so, it relies upon the setting of a 32-byte value to be an atomic
195  operation. unfortunately, there is no simple way to notify a class driver
196  which wants to know that the device behavior requires updating.
197 
198  Not ready events may be sent every second. For example, if we were
199  to minimize the number of asynchronous notifications, an application may
200  register just after a large busy time was reported. This would then
201  prevent the application from knowing the device was busy until some
202  arbitrarily chosen timeout has occurred. Also, the GESN request would
203  have to still occur, since it checks for non-busy events (such as user
204  keybutton presses and media change events) as well. The specification
205  states that the lower-numered events get reported first, so busy events,
206  while repeating, will only be reported when all other events have been
207  cleared from the device.
208 
209 --*/
210 {
212  PMEDIA_CHANGE_DETECTION_INFO info = DeviceExtension->MediaChangeDetectionInfo;
213  LONG dataLength = 0;
214  LONG requiredLength = 0;
215  BOOLEAN inHomePosition = FALSE;
216 
217  PAGED_CODE();
218 
219  // note: don't allocate anything in this routine so that we can
220  // always just 'return'.
221  *ResendImmediately = FALSE;
222 
223  if (Header->NEA)
224  {
225  return status;
226  }
227  if (Header->NotificationClass == NOTIFICATION_NO_CLASS_EVENTS)
228  {
229  return status;
230  }
231 
232  // HACKHACK - REF #0001
233  // This loop is only taken initially, due to the inability to reliably
234  // auto-detect drives that report events correctly at boot. When we
235  // detect this behavior during the normal course of running, we will
236  // disable the hack, allowing more efficient use of the system. This
237  // should occur "nearly" instantly, as the drive should have multiple
238  // events queue'd (ie. power, morphing, media).
239  if (info->Gesn.HackEventMask)
240  {
241  // all events use the low four bytes of zero to indicate
242  // that there was no change in status.
243  UCHAR thisEvent = Header->ClassEventData[0] & 0xf;
244  UCHAR lowestSetBit;
245  UCHAR thisEventBit = (1 << Header->NotificationClass);
246 
247  if (!TEST_FLAG(info->Gesn.EventMask, thisEventBit))
248  {
249  // The drive is reporting an event that wasn't requested
251  }
252 
253  // some bit magic here... this results in the lowest set bit only
254  lowestSetBit = info->Gesn.EventMask;
255  lowestSetBit &= (info->Gesn.EventMask - 1);
256  lowestSetBit ^= (info->Gesn.EventMask);
257 
258  if (thisEventBit != lowestSetBit)
259  {
260  // HACKHACK - REF #0001
261  // the first time we ever see an event set that is not the lowest
262  // set bit in the request (iow, highest priority), we know that the
263  // hack is no longer required, as the device is ignoring "no change"
264  // events when a real event is waiting in the other requested queues.
265  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
266  "GESN::NONE: Compliant drive found, "
267  "removing GESN hack (%x, %x)\n",
268  thisEventBit, info->Gesn.EventMask));
269 
270  info->Gesn.HackEventMask = FALSE;
271  }
272  else if (thisEvent == 0) // NOTIFICATION_*_EVENT_NO_CHANGE
273  {
274  // HACKHACK - REF #0001
275  // note: this hack prevents poorly implemented firmware from constantly
276  // returning "No Event". we do this by cycling through the
277  // supported list of events here.
278  SET_FLAG(info->Gesn.NoChangeEventMask, thisEventBit);
279  CLEAR_FLAG(info->Gesn.EventMask, thisEventBit);
280 
281  // if we have cycled through all supported event types, then
282  // we need to reset the events we are asking about. else we
283  // want to resend this request immediately in case there was
284  // another event pending.
285  if (info->Gesn.EventMask == 0)
286  {
287  info->Gesn.EventMask = info->Gesn.NoChangeEventMask;
288  info->Gesn.NoChangeEventMask = 0;
289  }
290  else
291  {
292  *ResendImmediately = TRUE;
293  }
294  return status;
295  }
296 
297  } // end if (info->Gesn.HackEventMask)
298 
299  dataLength = (Header->EventDataLength[0] << 8) |
300  (Header->EventDataLength[1] & 0xff);
301  dataLength -= 2;
302  requiredLength = 4; // all events are four bytes
303 
304  if (dataLength < requiredLength)
305  {
306  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN,
307  "error - GESN returned only %x bytes data for fdo %p\n",
308  dataLength, DeviceExtension->DeviceObject));
309 
311  }
312 
313  if (dataLength > requiredLength)
314  {
315  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN,
316  "error - GESN returned too many (%x) bytes data for fdo %p\n",
317  dataLength, DeviceExtension->DeviceObject));
318  }
319 
320  if ((Header->ClassEventData[0] & 0xf) == 0)
321  {
322  // a zero event is a "no change event, so do not retry
323  return status;
324  }
325 
326  // because a event other than "no change" occurred,
327  // we should immediately resend this request.
328  *ResendImmediately = TRUE;
329 
330  switch (Header->NotificationClass)
331  {
332 
334  {
335  PNOTIFICATION_OPERATIONAL_STATUS opChangeInfo =
336  (PNOTIFICATION_OPERATIONAL_STATUS)(Header->ClassEventData);
337  ULONG event;
338 
340  {
341  break;
342  }
343 
344  event = (opChangeInfo->Operation[0] << 8) |
345  (opChangeInfo->Operation[1] ) ;
346 
347  // Workaround some hardware that is buggy but prevalent in the market
348  // This hardware has the property that it will report OpChange events repeatedly,
349  // causing us to retry immediately so quickly that we will eventually disable
350  // GESN to prevent an infinite loop.
351  // (only one valid OpChange event type now, only two ever defined)
352  if (info->MediaChangeRetryCount >= 4)
353  {
354  //
355  // HACKHACK - REF #0002
356  // Some drives incorrectly report OpChange/Change (001b/0001h) events
357  // continuously when the tray has been ejected. This causes this routine
358  // to set ResendImmediately to "TRUE", and that results in our cycling
359  // 32 times immediately resending. At that point, we give up detecting
360  // the infinite retry loop, and disable GESN on these drives. This
361  // prevents Media Eject Request (from eject button) from being reported.
362  // Thus, instead we should attempt to workaround this issue by detecting
363  // this behavior.
364  //
365 
366  static UCHAR const OpChangeMask = 0x02;
367 
368  // At least one device reports "temporarily busy" (which is useless) on eject
369  // At least one device reports "OpChange" repeatedly when re-inserting media
370  // All seem to work well using this workaround
371 
372  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_MCN,
373  "GESN OpChange events are broken. Working around this problem in software (for WDFDEVICE %p)\n",
374  DeviceExtension->Device));
375 
376  // OpChange is not the only bit set -- Media class is required....
377  NT_ASSERT(CountOfSetBitsUChar(info->Gesn.EventMask) != 1);
378 
379  // Force the use of the hackhack (ref #0001) to workaround the
380  // issue noted this hackhack (ref #0002).
381  SET_FLAG(info->Gesn.NoChangeEventMask, OpChangeMask);
382  CLEAR_FLAG(info->Gesn.EventMask, OpChangeMask);
383  info->Gesn.HackEventMask = TRUE;
384 
385  // don't request the opChange event again. use the method
386  // defined by hackhack (ref #0001) as the workaround.
387  if (info->Gesn.EventMask == 0)
388  {
389  info->Gesn.EventMask = info->Gesn.NoChangeEventMask;
390  info->Gesn.NoChangeEventMask = 0;
391  *ResendImmediately = FALSE;
392  }
393  else
394  {
395  *ResendImmediately = TRUE;
396  }
397 
398  break;
399  }
400 
401 
404  {
405  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
406  "GESN says features added/changed for WDFDEVICE %p\n",
407  DeviceExtension->Device));
408 
409  // don't notify that new media arrived, just set the
410  // DO_VERIFY to force a FS reload.
411 
412  if (IsVolumeMounted(DeviceExtension->DeviceObject))
413  {
414  SET_FLAG(DeviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME);
415  }
416 
417  // Call error handler with
418  // a "fake" media change error in case it needs to update
419  // internal structures as though a media change occurred.
420  {
421  SCSI_REQUEST_BLOCK srb = {0};
422  SENSE_DATA sense = {0};
423  NTSTATUS tempStatus;
424  BOOLEAN retry;
425 
426  tempStatus = STATUS_MEDIA_CHANGED;
427  retry = FALSE;
428 
429  srb.CdbLength = 6;
430  srb.Length = sizeof(SCSI_REQUEST_BLOCK);
432  srb.SenseInfoBuffer = &sense;
433  srb.SenseInfoBufferLength = sizeof(SENSE_DATA);
434 
435  sense.AdditionalSenseLength = sizeof(SENSE_DATA) -
436  RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseLength);
437 
440 
441  if (DeviceExtension->DeviceAdditionalData.ErrorHandler)
442  {
443  DeviceExtension->DeviceAdditionalData.ErrorHandler(DeviceExtension,
444  &srb,
445  &tempStatus,
446  &retry);
447  }
448  } // end error handler
449 
450  }
451  break;
452  }
453 
455  {
456  PNOTIFICATION_EXTERNAL_STATUS externalInfo =
457  (PNOTIFICATION_EXTERNAL_STATUS)(Header->ClassEventData);
458  DEVICE_EVENT_EXTERNAL_REQUEST externalData = {0};
459 
460  // unfortunately, due to time constraints, we will only notify
461  // about keys being pressed, and not released. this makes keys
462  // single-function, but simplifies the code significantly.
464  {
465  break;
466  }
467 
468  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
469  "GESN::EXTERNAL: Event: %x Status %x Req %x\n",
470  externalInfo->ExternalEvent, externalInfo->ExternalStatus,
471  (externalInfo->Request[0] << 8) | externalInfo->Request[1]
472  ));
473 
474  externalData.Version = 1;
475  externalData.DeviceClass = 0;
476  externalData.ButtonStatus = externalInfo->ExternalEvent;
477  externalData.Request = (externalInfo->Request[0] << 8) |
478  (externalInfo->Request[1] & 0xff);
479  KeQuerySystemTime(&(externalData.SystemTime));
481 
482  DeviceSendNotification(DeviceExtension,
483  &GUID_IO_DEVICE_EXTERNAL_REQUEST,
485  &externalData);
486 
487  return status;
488  }
489 
491  {
492  PNOTIFICATION_MEDIA_STATUS mediaInfo =
493  (PNOTIFICATION_MEDIA_STATUS)(Header->ClassEventData);
494 
495  if ((mediaInfo->MediaEvent == NOTIFICATION_MEDIA_EVENT_NEW_MEDIA) ||
497  {
498  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
499  "GESN::MEDIA ARRIVAL, Status %x\n",
500  mediaInfo->MediaStatus));
501 
502  if (IsVolumeMounted(DeviceExtension->DeviceObject))
503  {
504  SET_FLAG(DeviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME);
505  }
506  DeviceSetMediaChangeStateEx(DeviceExtension,
507  MediaPresent,
508  NULL);
509 
510  // If media is inserted into slot loading type, mark the device active
511  // to not power off.
512  if ((DeviceExtension->ZeroPowerODDInfo != NULL) &&
513  (DeviceExtension->ZeroPowerODDInfo->LoadingMechanism == LOADING_MECHANISM_CADDY) &&
514  (DeviceExtension->ZeroPowerODDInfo->Load == 0)) // Slot
515  {
516  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER,
517  "GesnDataInterpret: MediaArrival event detected, device marked as active\n"));
518 
519  DeviceMarkActive(DeviceExtension, TRUE, FALSE);
520  }
521  }
522  else if (mediaInfo->MediaEvent == NOTIFICATION_MEDIA_EVENT_MEDIA_REMOVAL)
523  {
524  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
525  "GESN::MEDIA REMOVAL, Status %x\n",
526  mediaInfo->MediaStatus));
527 
528  DeviceSetMediaChangeStateEx(DeviceExtension,
530  NULL);
531 
532  // If media is removed from slot loading type, start powering off the device
533  // if it is ZPODD capable.
534  if ((DeviceExtension->ZeroPowerODDInfo != NULL) &&
535  (DeviceExtension->ZeroPowerODDInfo->LoadingMechanism == LOADING_MECHANISM_CADDY) &&
536  (DeviceExtension->ZeroPowerODDInfo->Load == 0)) // Slot
537  {
538  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER,
539  "GesnDataInterpret: MediaRemoval event detected, device marked as idle\n"));
540 
541  DeviceMarkActive(DeviceExtension, FALSE, FALSE);
542  }
543  }
544  else if (mediaInfo->MediaEvent == NOTIFICATION_MEDIA_EVENT_EJECT_REQUEST)
545  {
546  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
547  "GESN::MEDIA EJECTION, Status %x\n",
548  mediaInfo->MediaStatus));
549 
550  DeviceSendNotification(DeviceExtension,
551  &GUID_IO_MEDIA_EJECT_REQUEST,
552  0,
553  NULL);
554  }
555 
556  break;
557  }
558 
559  case NOTIFICATION_DEVICE_BUSY_CLASS_EVENTS: // lowest priority events...
560  {
561  PNOTIFICATION_BUSY_STATUS busyInfo =
562  (PNOTIFICATION_BUSY_STATUS)(Header->ClassEventData);
563  DEVICE_EVENT_BECOMING_READY busyData = {0};
564 
565  // else we want to report the approximated time till it's ready.
566  busyData.Version = 1;
567  busyData.Reason = busyInfo->DeviceBusyStatus;
568  busyData.Estimated100msToReady = (busyInfo->Time[0] << 8) |
569  (busyInfo->Time[1] & 0xff);
570 
571  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
572  "GESN::BUSY: Event: %x Status %x Time %x\n",
573  busyInfo->DeviceBusyEvent, busyInfo->DeviceBusyStatus,
574  busyData.Estimated100msToReady
575  ));
576 
577  // Ignore the notification if the time is small
579  {
580  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
581  "GesnDataInterpret: media BECOMING_READY\n"));
582 
583  DeviceSendNotification(DeviceExtension,
584  &GUID_IO_DEVICE_BECOMING_READY,
586  &busyData);
587  }
588 
589  // If manual loading operation is observed for slot loading type, start powering off the device
590  // if it is ZPODD capable.
591  if ((DeviceExtension->ZeroPowerODDInfo != NULL) &&
592  (DeviceExtension->ZeroPowerODDInfo->LoadingMechanism == LOADING_MECHANISM_TRAY) &&
593  (DeviceExtension->ZeroPowerODDInfo->Load == 0) && // Drawer
596  {
597  inHomePosition = DeviceZPODDIsInHomePosition(DeviceExtension);
598 
599  if (inHomePosition == FALSE)
600  {
601  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER,
602  "GesnDataInterpret: LoChange event detected, device marked as active\n"));
603 
604  DeviceMarkActive(DeviceExtension, TRUE, FALSE);
605  }
606  else
607  {
608  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER,
609  "GesnDataInterpret: LoChange event detected, device marked as idle\n"));
610 
611  DeviceMarkActive(DeviceExtension, FALSE, FALSE);
612  }
613  }
614 
615  break;
616  }
617 
618  default:
619  {
620  break;
621  }
622 
623  } // end switch on notification class
624 
625  return status;
626 }
627 
628 
629 VOID
631  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
634  )
635 /*++
636 
637 Routine Description:
638 
639  This routine will (if appropriate) set the media change event for the
640  device. The event will be set if the media state is changed and
641  media change events are enabled. Otherwise the media state will be
642  tracked but the event will not be set.
643 
644  This routine will lock out the other media change routines if possible
645  but if not a media change notification may be lost after the enable has
646  been completed.
647 
648 Arguments:
649 
650  DeviceExtension - the device extension
651 
652  NewState - new state for setting
653 
654  OldState - optional storage for the old state
655 
656 Return Value:
657 
658  none
659 
660 --*/
661 {
662 #if DBG
663  LPCSTR states[] = {"Unknown", "Present", "Not Present", "Unavailable"};
664 #endif
665  MEDIA_CHANGE_DETECTION_STATE oldMediaState;
666  PMEDIA_CHANGE_DETECTION_INFO info = DeviceExtension->MediaChangeDetectionInfo;
667  CLASS_MEDIA_CHANGE_CONTEXT mcnContext;
668 
669  if (!((NewState >= MediaUnknown) && (NewState <= MediaUnavailable)))
670  {
671  return;
672  }
673 
674  if (info == NULL)
675  {
676  return;
677  }
678 
679  oldMediaState = info->LastKnownMediaDetectionState;
680  if (OldState)
681  {
682  *OldState = oldMediaState;
683  }
684 
685  info->LastKnownMediaDetectionState = NewState;
686 
687  // Increment MediaChangeCount on transition to MediaPresent
688  if (NewState == MediaPresent && oldMediaState != NewState)
689  {
690  InterlockedIncrement((PLONG)&DeviceExtension->MediaChangeCount);
691  }
692 
693  if (info->MediaChangeDetectionDisableCount != 0)
694  {
695 #if DBG
696  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
697  "DeviceInternalSetMediaChangeState: MCN not enabled, state "
698  "changed from %s to %s\n",
699  states[oldMediaState], states[NewState]));
700 #endif
701  return;
702  }
703 #if DBG
704  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
705  "DeviceInternalSetMediaChangeState: State change from %s to %s\n",
706  states[oldMediaState], states[NewState]));
707 #endif
708 
709  if (info->LastReportedMediaDetectionState == info->LastKnownMediaDetectionState)
710  {
711  // Media is in the same state as we reported last time, no need to report again.
712  return;
713  }
714 
715  // make the data useful -- it used to always be zero.
716  mcnContext.MediaChangeCount = DeviceExtension->MediaChangeCount;
717  mcnContext.NewState = NewState;
718 
719  if (NewState == MediaPresent)
720  {
721  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
722  "DeviceInternalSetMediaChangeState: Reporting media ARRIVAL\n"));
723 
724  DeviceSendNotification(DeviceExtension,
725  &GUID_IO_MEDIA_ARRIVAL,
727  &mcnContext);
728  }
729  else if ((NewState == MediaNotPresent) || (NewState == MediaUnavailable))
730  {
731  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
732  "DeviceInternalSetMediaChangeState: Reporting media REMOVAL\n"));
733  DeviceSendNotification(DeviceExtension,
734  &GUID_IO_MEDIA_REMOVAL,
736  &mcnContext);
737  }
738  else
739  {
740  // Don't notify of changed going to unknown.
741  return;
742  }
743 
744  info->LastReportedMediaDetectionState = info->LastKnownMediaDetectionState;
745 
746  return;
747 } // end DeviceInternalSetMediaChangeState()
748 
749 
750 VOID
752  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
755  )
756 /*++
757 
758 Routine Description:
759 
760  This routine will (if appropriate) set the media change event for the
761  device. The event will be set if the media state is changed and
762  media change events are enabled. Otherwise the media state will be
763  tracked but the event will not be set.
764 
765 Arguments:
766 
767  DeviceExtension - the device extension
768 
769  NewState - new state for setting
770 
771  OldState - optional storage for the old state
772 
773 Return Value:
774 
775  none
776 
777 --*/
778 {
779  PMEDIA_CHANGE_DETECTION_INFO info = DeviceExtension->MediaChangeDetectionInfo;
782 
783  // timeout value must be 0, as this function can be called at DISPATCH_LEVEL.
784  zero.QuadPart = 0;
785 
786  if (info == NULL)
787  {
788  return;
789  }
790 
791  status = KeWaitForMutexObject(&info->MediaChangeMutex,
792  Executive,
793  KernelMode,
794  FALSE,
795  &zero);
796 
797  if (status == STATUS_TIMEOUT)
798  {
799  // Someone else is in the process of setting the media state.
800  return;
801  }
802 
803  // Change the media present state and signal an event, if applicable
804  DeviceInternalSetMediaChangeState(DeviceExtension, NewState, OldState);
805 
806  KeReleaseMutex(&info->MediaChangeMutex, FALSE);
807 
808  return;
809 } // end DeviceSetMediaChangeStateEx()
810 
811 
813 VOID
814 DeviceSendDelayedMediaChangeNotifications(
815  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
816  )
817 /*++
818 
819 Routine Description:
820 
821  This routine sends the so-called delayed media change notifications.
822  These notifications get accumulated while the MCN mechanism is disabled
823  and need to be sent to the application on MCN enabling, if MCN enabling
824  happens as a part of exclusive access unlock and the application has not
825  requested us explicitly to not send the delayed notifications.
826 
827 Arguments:
828 
829  DeviceExtension - the device extension
830 
831 Return Value:
832 
833  none
834 
835 --*/
836 {
837  PMEDIA_CHANGE_DETECTION_INFO info = DeviceExtension->MediaChangeDetectionInfo;
840 
841  PAGED_CODE();
842 
843  zero.QuadPart = 0;
844 
845  if (info == NULL)
846  {
847  return;
848  }
849 
850  status = KeWaitForMutexObject(&info->MediaChangeMutex,
851  Executive,
852  KernelMode,
853  FALSE,
854  &zero);
855 
856  if (status == STATUS_TIMEOUT)
857  {
858  // Someone else is in the process of setting the media state.
859  // That's totally okay, we'll send delayed notifications later.
860  return;
861  }
862 
863  // If the last reported state and the last known state are different and
864  // MCN is enabled, generate a notification based on the last known state.
865  if ((info->LastKnownMediaDetectionState != info->LastReportedMediaDetectionState) &&
866  (info->MediaChangeDetectionDisableCount == 0))
867  {
868  DeviceInternalSetMediaChangeState(DeviceExtension, info->LastKnownMediaDetectionState, NULL);
869  }
870 
871  KeReleaseMutex(&info->MediaChangeMutex, FALSE);
872 
873  return;
874 }
875 
876 
878 NTSTATUS
879 RequestSetupMcnRequest(
880  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
882 )
883 /*++
884 
885 Routine Description:
886 
887  This routine sets up the fields of the request for MCN
888 
889 Arguments:
890  DeviceExtension - device context
891 
892  UseGesn - If TRUE, the device supports GESN and it's currently the mechanism for MCN
893 
894 Return Value:
895  NTSTATUS
896 
897 --*/
898 {
901  PIRP irp;
902  PIO_STACK_LOCATION nextIrpStack;
903  PCDB cdb;
904  PVOID buffer;
906  PMEDIA_CHANGE_DETECTION_INFO info = DeviceExtension->MediaChangeDetectionInfo;
907 
908  PAGED_CODE();
909 
910  irp = WdfRequestWdmGetIrp(info->MediaChangeRequest);
911  NT_ASSERT(irp != NULL);
912 
913  // deassign the MdlAddress, this is the value we assign explicitly.
914  // this is to prevent WdfRequestReuse to release the Mdl unexpectly.
915  if (irp->MdlAddress)
916  {
917  irp->MdlAddress = NULL;
918  }
919 
920  if (NT_SUCCESS(status))
921  {
922  // Setup the IRP to perform a test unit ready.
926 
927  status = WdfRequestReuse(info->MediaChangeRequest, &params);
928  }
929 
930  if (NT_SUCCESS(status))
931  {
932  // Format the request.
933  status = WdfIoTargetFormatRequestForInternalIoctlOthers(DeviceExtension->IoTarget,
934  info->MediaChangeRequest,
936  NULL, NULL,
937  NULL, NULL,
938  NULL, NULL);
939 
940  if (!NT_SUCCESS(status))
941  {
942  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
943  "RequestSetupMcnRequest: WdfIoTargetFormatRequestForInternalIoctlOthers failed, %!STATUS!\n",
944  status));
945  }
946  }
947 
948  if (NT_SUCCESS(status))
949  {
950  RequestClearSendTime(info->MediaChangeRequest);
951 
952  nextIrpStack = IoGetNextIrpStackLocation(irp);
953 
954  nextIrpStack->Flags = SL_OVERRIDE_VERIFY_VOLUME;
956  nextIrpStack->Parameters.Scsi.Srb = &(info->MediaChangeSrb);
957 
958  // Prepare the SRB for execution.
959  srb = nextIrpStack->Parameters.Scsi.Srb;
960  buffer = info->SenseBuffer;
961  RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
963 
964  srb->QueueTag = SP_UNTAGGED;
966  srb->Length = sizeof(SCSI_REQUEST_BLOCK);
968  srb->SenseInfoBuffer = buffer;
969  srb->SrbStatus = 0;
970  srb->ScsiStatus = 0;
971  srb->OriginalRequest = irp;
973 
974  srb->SrbFlags = DeviceExtension->SrbFlags;
975  SET_FLAG(srb->SrbFlags, info->SrbFlags);
976 
977  if (!UseGesn)
978  {
980  srb->CdbLength = 6;
981  srb->DataTransferLength = 0;
983  nextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_NONE;
984  srb->DataBuffer = NULL;
985  srb->DataTransferLength = 0;
986  irp->MdlAddress = NULL;
987 
988  cdb = (PCDB) &srb->Cdb[0];
989  cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
990  }
991  else
992  {
993  NT_ASSERT(info->Gesn.Buffer);
994 
995  srb->TimeOutValue = GESN_TIMEOUT_VALUE; // much shorter timeout for GESN
996 
997  srb->CdbLength = 10;
999  nextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
1000  srb->DataBuffer = info->Gesn.Buffer;
1001  srb->DataTransferLength = info->Gesn.BufferSize;
1002  irp->MdlAddress = info->Gesn.Mdl;
1003 
1004  cdb = (PCDB) &srb->Cdb[0];
1006  cdb->GET_EVENT_STATUS_NOTIFICATION.Immediate = 1;
1007  cdb->GET_EVENT_STATUS_NOTIFICATION.EventListLength[0] = (UCHAR)((info->Gesn.BufferSize) >> 8);
1008  cdb->GET_EVENT_STATUS_NOTIFICATION.EventListLength[1] = (UCHAR)((info->Gesn.BufferSize) & 0xff);
1009  cdb->GET_EVENT_STATUS_NOTIFICATION.NotificationClassRequest = info->Gesn.EventMask;
1010  }
1011  }
1012 
1013  return status;
1014 }
1015 
1016 
1017 VOID
1018 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
1020  _In_ WDFWORKITEM WorkItem
1021  )
1022 /*++
1023 
1024 Routine Description:
1025 
1026  Work item routine to set the hack flag in the registry to disable GESN
1027  This routine is invoked when the device reports TOO many events that affects system
1028 
1029 Arguments:
1030  WorkItem - the work item be perfromed.
1031 
1032 Return Value:
1033  None
1034 
1035 --*/
1036 {
1037  WDFDEVICE device = WdfWorkItemGetParentObject(WorkItem);
1038  PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(device);
1039 
1040  PAGED_CODE();
1041 
1042  //
1043  // Set the hack flag in the registry
1044  //
1045  DeviceSetParameter(deviceExtension,
1049 
1050  WdfObjectDelete(WorkItem);
1051 
1052  return;
1053 }
1054 
1056 BOOLEAN
1057 RequestPostWorkMcnRequest(
1058  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
1059  )
1060 /*++
1061 
1062 Routine Description:
1063 
1064  This routine handles the completion of the test unit ready irps used to
1065  determine if the media has changed. If the media has changed, this code
1066  signals the named event to wake up other system services that react to
1067  media change (aka AutoPlay).
1068 
1069 Arguments:
1070 
1071  DeviceExtension - the device context
1072 
1073 Return Value:
1074 
1075  BOOLEAN - TRUE (needs retry); FALSE (shoule not retry)
1076 
1077 --*/
1078 {
1080  PMEDIA_CHANGE_DETECTION_INFO info = DeviceExtension->MediaChangeDetectionInfo;
1081  PIRP irp;
1082  BOOLEAN retryImmediately = FALSE;
1083 
1084  PAGED_CODE();
1085 
1086  NT_ASSERT(info->MediaChangeRequest != NULL);
1087  irp = WdfRequestWdmGetIrp(info->MediaChangeRequest);
1088 
1089  NT_ASSERT(!TEST_FLAG(info->MediaChangeSrb.SrbStatus, SRB_STATUS_QUEUE_FROZEN));
1090 
1091  // use InterpretSenseInfo routine to check for media state, and also
1092  // to call ClassError() with correct parameters.
1093  if (SRB_STATUS(info->MediaChangeSrb.SrbStatus) != SRB_STATUS_SUCCESS)
1094  {
1095  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN, "MCN request - failed - srb status=%x, sense=%x/%x/%x.\n",
1096  info->MediaChangeSrb.SrbStatus,
1097  ((PSENSE_DATA)(info->MediaChangeSrb.SenseInfoBuffer))->SenseKey,
1098  ((PSENSE_DATA)(info->MediaChangeSrb.SenseInfoBuffer))->AdditionalSenseCode,
1099  ((PSENSE_DATA)(info->MediaChangeSrb.SenseInfoBuffer))->AdditionalSenseCodeQualifier));
1100 
1101  if (SRB_STATUS(info->MediaChangeSrb.SrbStatus) != SRB_STATUS_NOT_POWERED)
1102  {
1103  // Release the queue if it is frozen.
1104  if (info->MediaChangeSrb.SrbStatus & SRB_STATUS_QUEUE_FROZEN)
1105  {
1106  DeviceReleaseQueue(DeviceExtension->Device);
1107  }
1108 
1109  RequestSenseInfoInterpret(DeviceExtension,
1110  info->MediaChangeRequest,
1111  &info->MediaChangeSrb,
1112  0,
1113  &status,
1114  NULL);
1115  }
1116  }
1117  else
1118  {
1119  DeviceExtension->PrivateFdoData->LoggedTURFailureSinceLastIO = FALSE;
1120 
1121  if (!info->Gesn.Supported)
1122  {
1123  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
1124  "MCN request - succeeded (GESN NOT supported, setting MediaPresent).\n"));
1125 
1126  // success != media for GESN case
1127  DeviceSetMediaChangeStateEx(DeviceExtension,
1128  MediaPresent,
1129  NULL);
1130  }
1131  else
1132  {
1133  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_MCN,
1134  "MCN request - succeeded (GESN supported).\n"));
1135  }
1136  }
1137 
1138  if (info->Gesn.Supported)
1139  {
1140  if (status == STATUS_DATA_OVERRUN)
1141  {
1142  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "MCN Request - Data Overrun\n"));
1144  }
1145 
1146  if (!NT_SUCCESS(status))
1147  {
1148  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "MCN Request: GESN failed with status %x\n", status));
1149  }
1150  else
1151  {
1152  // for GESN, need to interpret the results of the data.
1153  // this may also require an immediate retry
1154  if (irp->IoStatus.Information == 8 )
1155  {
1156  GesnDataInterpret(DeviceExtension,
1157  (PVOID)info->Gesn.Buffer,
1158  &retryImmediately);
1159  }
1160 
1161  } // end of NT_SUCCESS(status)
1162 
1163  } // end of Info->Gesn.Supported
1164 
1165  // free port-allocated sense buffer, if any.
1166  if (PORT_ALLOCATED_SENSE(DeviceExtension, &info->MediaChangeSrb))
1167  {
1168  FREE_PORT_ALLOCATED_SENSE_BUFFER(DeviceExtension, &info->MediaChangeSrb);
1169  }
1170 
1171  // Remember the IRP and SRB for use the next time.
1173  IoGetNextIrpStackLocation(irp)->Parameters.Scsi.Srb = &info->MediaChangeSrb;
1174 
1175  // run a sanity check to make sure we're not recursing continuously
1176  if (retryImmediately)
1177  {
1178  info->MediaChangeRetryCount++;
1179 
1180  if (info->MediaChangeRetryCount > MAXIMUM_IMMEDIATE_MCN_RETRIES)
1181  {
1182  // Disable GESN on this device.
1183  // Create a work item to set the value in the registry
1184  WDF_OBJECT_ATTRIBUTES attributes;
1185  WDF_WORKITEM_CONFIG workitemConfig;
1186  WDFWORKITEM workItem;
1187 
1188  WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
1189  attributes.ParentObject = DeviceExtension->Device;
1190 
1191  WDF_WORKITEM_CONFIG_INIT(&workitemConfig, DeviceDisableGesn);
1192  workitemConfig.AutomaticSerialization = FALSE;
1193 
1194  status = WdfWorkItemCreate(&workitemConfig,
1195  &attributes,
1196  &workItem);
1197 
1198  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "MCN Request: Disabling GESN for WDFDEVICE %p\n", DeviceExtension->Device));
1199 
1200  if (NT_SUCCESS(status))
1201  {
1202  WdfWorkItemEnqueue(workItem);
1203  }
1204 
1205  info->Gesn.Supported = FALSE;
1206  info->Gesn.EventMask = 0;
1207  info->Gesn.BufferSize = 0;
1208  info->MediaChangeRetryCount = 0;
1209  retryImmediately = FALSE;
1210  // should we log an error in event log?
1211  }
1212  }
1213  else
1214  {
1215  info->MediaChangeRetryCount = 0;
1216  }
1217 
1218  return retryImmediately;
1219 }
1220 
1221 
1223 BOOLEAN
1224 RequestSendMcnRequest(
1225  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
1226  )
1227 /*++
1228 
1229 Routine Description:
1230 
1231  This routine sends the formatted MCN request sychronizely to lower driver.
1232 
1233 Arguments:
1234 
1235  DeviceExtension - the device context
1236 
1237 Return Value:
1238  BOOLEAN - TRUE (requst successfully sent); FALSE (request failed to send)
1239 
1240 --*/
1241 {
1242  BOOLEAN requestSent = FALSE;
1243  PMEDIA_CHANGE_DETECTION_INFO info = DeviceExtension->MediaChangeDetectionInfo;
1244 
1245  PAGED_CODE();
1246 
1247  RequestSend(DeviceExtension,
1248  info->MediaChangeRequest,
1249  DeviceExtension->IoTarget,
1251  &requestSent);
1252 
1253  return requestSent;
1254 } // end RequestSendMcnRequest()
1255 
1256 
1257 
1259 NTSTATUS
1260 DeviceInitializeMcn(
1261  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
1263  )
1264 /*++
1265 
1266 Routine Description:
1267 
1268  This routine initialize the contents of MCN structure.
1269 
1270 Arguments:
1271 
1272  DeviceExtension - the device extension
1273 
1274  AllowDriveToSleep - for CDROM, this parameter should be always FALSE
1275 
1276 Return Value:
1277  NTSTATUS
1278 
1279 --*/
1280 {
1282  PMEDIA_CHANGE_DETECTION_INFO mediaChangeInfo = NULL;
1283  PIRP irp = NULL;
1284  PVOID senseBuffer = NULL;
1285  WDF_OBJECT_ATTRIBUTES attributes;
1286 
1287  PAGED_CODE();
1288 
1289  if (DeviceExtension->MediaChangeDetectionInfo != NULL)
1290  {
1291  //Already initialized.
1292  return STATUS_SUCCESS;
1293  }
1294 
1295  DeviceExtension->KernelModeMcnContext.FileObject = (PVOID)-1;
1296  DeviceExtension->KernelModeMcnContext.DeviceObject = (PVOID)-1;
1297  DeviceExtension->KernelModeMcnContext.LockCount = 0;
1298  DeviceExtension->KernelModeMcnContext.McnDisableCount = 0;
1299 
1300  mediaChangeInfo = ExAllocatePoolWithTag(NonPagedPoolNx,
1303 
1304  if (mediaChangeInfo == NULL)
1305  {
1307  }
1308  else
1309  {
1310  RtlZeroMemory(mediaChangeInfo, sizeof(MEDIA_CHANGE_DETECTION_INFO));
1311  }
1312 
1313  if (NT_SUCCESS(status))
1314  {
1315  if ((DeviceExtension->PowerDescriptor != NULL) &&
1316  (DeviceExtension->PowerDescriptor->AsynchronousNotificationSupported != FALSE) &&
1317  (!TEST_FLAG(DeviceExtension->PrivateFdoData->HackFlags, FDO_HACK_NO_ASYNCHRONOUS_NOTIFICATION)))
1318  {
1319  mediaChangeInfo->AsynchronousNotificationSupported = TRUE;
1320  }
1321  }
1322 
1323  // Allocate an IRP to carry the IOCTL_MCN_SYNC_FAKE_IOCTL.
1324  if (NT_SUCCESS(status))
1325  {
1326  irp = IoAllocateIrp(DeviceExtension->DeviceObject->StackSize, FALSE);
1327 
1328  if (irp == NULL)
1329  {
1331  }
1332  }
1333 
1334  if (NT_SUCCESS(status))
1335  {
1338  attributes.ParentObject = DeviceExtension->Device;
1339  status = WdfRequestCreate(&attributes,
1340  DeviceExtension->IoTarget,
1341  &mediaChangeInfo->MediaChangeRequest);
1342  }
1343 
1344  if (NT_SUCCESS(status))
1345  {
1346  // Preformat the media change request. With this being done, we never need to worry about
1347  // WdfIoTargetFormatRequestForInternalIoctlOthers ever failing later.
1348  status = WdfIoTargetFormatRequestForInternalIoctlOthers(DeviceExtension->IoTarget,
1349  mediaChangeInfo->MediaChangeRequest,
1351  NULL, NULL,
1352  NULL, NULL,
1353  NULL, NULL);
1354  }
1355 
1356  if (NT_SUCCESS(status))
1357  {
1358  senseBuffer = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
1361  if (senseBuffer == NULL)
1362  {
1364  }
1365  }
1366 
1367  if (NT_SUCCESS(status))
1368  {
1369  mediaChangeInfo->MediaChangeSyncIrp = irp;
1370  mediaChangeInfo->SenseBuffer = senseBuffer;
1371 
1372  // Set default values for the media change notification
1373  // configuration.
1374  mediaChangeInfo->MediaChangeDetectionDisableCount = 0;
1375 
1376  // Assume that there is initially no media in the device
1377  // only notify upper layers if there is something there
1378  mediaChangeInfo->LastKnownMediaDetectionState = MediaUnknown;
1379  mediaChangeInfo->LastReportedMediaDetectionState = MediaUnknown;
1380 
1381  // setup all extra flags we'll be setting for this irp
1382  mediaChangeInfo->SrbFlags = 0;
1383 
1384  SET_FLAG(mediaChangeInfo->SrbFlags, SRB_CLASS_FLAGS_LOW_PRIORITY);
1385  SET_FLAG(mediaChangeInfo->SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE);
1387 
1388  if (AllowDriveToSleep) //FALSE for CD/DVD devices
1389  {
1390  SET_FLAG(mediaChangeInfo->SrbFlags, SRB_FLAGS_NO_KEEP_AWAKE);
1391  }
1392 
1393  KeInitializeMutex(&mediaChangeInfo->MediaChangeMutex, 0x100);
1394 
1395  // It is ok to support media change events on this device.
1396  DeviceExtension->MediaChangeDetectionInfo = mediaChangeInfo;
1397 
1398  // check the device supports GESN or not, initialize GESN structure if it supports.
1399  {
1400  // This is only valid for type5 devices.
1401  NTSTATUS tempStatus = STATUS_SUCCESS;
1402 
1403  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
1404  "DeviceInitializeMcn: Testing for GESN\n"));
1405  tempStatus = DeviceInitializeGesn(DeviceExtension);
1406 
1407  if (NT_SUCCESS(tempStatus))
1408  {
1409  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
1410  "DeviceInitializeMcn: GESN available for %p\n",
1411  DeviceExtension->DeviceObject));
1412  NT_ASSERT(mediaChangeInfo->Gesn.Supported );
1413  NT_ASSERT(mediaChangeInfo->Gesn.Buffer != NULL);
1414  NT_ASSERT(mediaChangeInfo->Gesn.BufferSize != 0);
1415  NT_ASSERT(mediaChangeInfo->Gesn.EventMask != 0);
1416  }
1417  else
1418  {
1419  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
1420  "DeviceInitializeMcn: GESN *NOT* available for %p\n",
1421  DeviceExtension->DeviceObject));
1422  NT_ASSERT(!mediaChangeInfo->Gesn.Supported);
1423  NT_ASSERT(mediaChangeInfo->Gesn.Buffer == NULL);
1424  NT_ASSERT(mediaChangeInfo->Gesn.BufferSize == 0);
1425  NT_ASSERT(mediaChangeInfo->Gesn.EventMask == 0);
1426  mediaChangeInfo->Gesn.Supported = FALSE; // just in case....
1427  }
1428  }
1429  }
1430 
1431  if (NT_SUCCESS(status))
1432  {
1433  // Register for display state change on AOAC capable systems so we can put the
1434  // device to low power state when not required.
1435  if (mediaChangeInfo->DisplayStateCallbackHandle == NULL)
1436  {
1437  POWER_PLATFORM_INFORMATION PlatformInfo = {0};
1438 
1439  status = ZwPowerInformation(PlatformInformation,
1440  NULL,
1441  0,
1442  &PlatformInfo,
1443  sizeof(PlatformInfo));
1444 
1445  if (NT_SUCCESS(status) && PlatformInfo.AoAc)
1446  {
1447  PoRegisterPowerSettingCallback(DeviceExtension->DeviceObject,
1448  &GUID_CONSOLE_DISPLAY_STATE,
1450  DeviceExtension,
1451  &mediaChangeInfo->DisplayStateCallbackHandle);
1452  }
1453 
1454  // Ignore any failures above.
1456  }
1457  }
1458 
1459  if (!NT_SUCCESS(status))
1460  {
1461  if (irp != NULL)
1462  {
1463  IoFreeIrp(irp);
1464  }
1465  FREE_POOL(senseBuffer);
1466  FREE_POOL(mediaChangeInfo);
1467  }
1468 
1469  return status;
1470 
1471 } // end DeviceInitializeMcn()
1472 
1473 
1475 NTSTATUS
1476 DeviceInitializeGesn(
1477  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
1478  )
1479 /*++
1480 
1481 Routine Description:
1482 
1483  This routine initialize the contents of GESN structure.
1484 
1485 Arguments:
1486 
1487  DeviceExtension - the device extension
1488 
1489 Return Value:
1490  NTSTATUS
1491 
1492 --*/
1493 {
1497  PSTORAGE_DEVICE_DESCRIPTOR deviceDescriptor = DeviceExtension->DeviceDescriptor;
1498  BOOLEAN retryImmediately = TRUE;
1499  ULONG i = 0;
1500  ULONG atapiResets = 0;
1501  PMEDIA_CHANGE_DETECTION_INFO info = DeviceExtension->MediaChangeDetectionInfo;
1502 
1503  PAGED_CODE();
1504 
1505  NT_ASSERT(info != NULL);
1506 
1507  // read if we already know the abilities of the device
1508  DeviceGetParameter(DeviceExtension,
1511  (PULONG)&detectionState);
1512 
1513  if (detectionState == CdromDetectionUnsupported)
1514  {
1516  }
1517 
1518  // check if the device has a hack flag saying never to try this.
1519  if (NT_SUCCESS(status) &&
1520  (TEST_FLAG(DeviceExtension->PrivateFdoData->HackFlags, FDO_HACK_GESN_IS_BAD)) )
1521  {
1522  DeviceSetParameter(DeviceExtension,
1527  }
1528 
1529  // else go through the process since we allocate buffers and
1530  // get all sorts of device settings.
1531  if (NT_SUCCESS(status))
1532  {
1533  if (info->Gesn.Buffer == NULL)
1534  {
1535  info->Gesn.Buffer = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
1537  CDROM_TAG_GESN);
1538  }
1539 
1540  if (info->Gesn.Buffer == NULL)
1541  {
1543  }
1544  }
1545 
1546  if (NT_SUCCESS(status))
1547  {
1548  if (info->Gesn.Mdl != NULL)
1549  {
1550  IoFreeMdl(info->Gesn.Mdl);
1551  }
1552 
1553  info->Gesn.Mdl = IoAllocateMdl(info->Gesn.Buffer,
1555  FALSE,
1556  FALSE,
1557  NULL);
1558  if (info->Gesn.Mdl == NULL)
1559  {
1561  }
1562  }
1563 
1564  if (NT_SUCCESS(status))
1565  {
1566  MmBuildMdlForNonPagedPool(info->Gesn.Mdl);
1567  info->Gesn.BufferSize = GESN_BUFFER_SIZE;
1568  info->Gesn.EventMask = 0;
1569 
1570  // all items are prepared to use GESN (except the event mask, so don't
1571  // optimize this part out!).
1572  //
1573  // now see if it really works. we have to loop through this because
1574  // many SAMSUNG (and one COMPAQ) drives timeout when requesting
1575  // NOT_READY events, even when the IMMEDIATE bit is set. :(
1576  //
1577  // using a drive list is cumbersome, so this might fix the problem.
1578  for (i = 0; (i < 16) && retryImmediately; i++)
1579  {
1580  status = RequestSetupMcnRequest(DeviceExtension, TRUE);
1581 
1582  if (!NT_SUCCESS(status))
1583  {
1584  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN,
1585  "Setup Mcn request failed %x for WDFDEVICE %p\n",
1586  status, DeviceExtension->Device));
1587  break;
1588  }
1589 
1590  NT_ASSERT(TEST_FLAG(info->MediaChangeSrb.SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE));
1591 
1592  status = DeviceSendRequestSynchronously(DeviceExtension->Device, info->MediaChangeRequest, TRUE);
1593 
1594  if (SRB_STATUS(info->MediaChangeSrb.SrbStatus) != SRB_STATUS_SUCCESS)
1595  {
1596  // Release the queue if it is frozen.
1597  if (info->MediaChangeSrb.SrbStatus & SRB_STATUS_QUEUE_FROZEN)
1598  {
1599  DeviceReleaseQueue(DeviceExtension->Device);
1600  }
1601 
1602  RequestSenseInfoInterpret(DeviceExtension,
1603  info->MediaChangeRequest,
1604  &(info->MediaChangeSrb),
1605  0,
1606  &status,
1607  NULL);
1608  }
1609 
1610  if ((deviceDescriptor->BusType == BusTypeAtapi) &&
1611  (info->MediaChangeSrb.SrbStatus == SRB_STATUS_BUS_RESET))
1612  {
1613  //
1614  // ATAPI unfortunately returns SRB_STATUS_BUS_RESET instead
1615  // of SRB_STATUS_TIMEOUT, so we cannot differentiate between
1616  // the two. if we get this status four time consecutively,
1617  // stop trying this command. it is too late to change ATAPI
1618  // at this point, so special-case this here. (07/10/2001)
1619  // NOTE: any value more than 4 may cause the device to be
1620  // marked missing.
1621  //
1622  atapiResets++;
1623  if (atapiResets >= 4)
1624  {
1626  break;
1627  }
1628  }
1629 
1630  if (status == STATUS_DATA_OVERRUN)
1631  {
1633  }
1634 
1636  (status == STATUS_TIMEOUT) ||
1639  {
1640  // with these error codes, we don't ever want to try this command
1641  // again on this device, since it reacts poorly.
1642  DeviceSetParameter( DeviceExtension,
1646  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN,
1647  "GESN test failed %x for WDFDEVICE %p\n",
1648  status, DeviceExtension->Device));
1649  break;
1650  }
1651 
1652  if (!NT_SUCCESS(status))
1653  {
1654  // this may be other errors that should not disable GESN
1655  // for all future start_device calls.
1656  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN,
1657  "GESN test failed %x for WDFDEVICE %p\n",
1658  status, DeviceExtension->Device));
1659  break;
1660  }
1661  else if (i == 0)
1662  {
1663  // the first time, the request was just retrieving a mask of
1664  // available bits. use this to mask future requests.
1665  header = (PNOTIFICATION_EVENT_STATUS_HEADER)(info->Gesn.Buffer);
1666 
1667  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
1668  "WDFDEVICE %p supports event mask %x\n",
1669  DeviceExtension->Device, header->SupportedEventClasses));
1670 
1671  if (TEST_FLAG(header->SupportedEventClasses,
1673  {
1674  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
1675  "GESN supports MCN\n"));
1676  }
1677  if (TEST_FLAG(header->SupportedEventClasses,
1679  {
1680  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
1681  "GESN supports DeviceBusy\n"));
1682  }
1683  if (TEST_FLAG(header->SupportedEventClasses,
1685  {
1686  if (TEST_FLAG(DeviceExtension->PrivateFdoData->HackFlags,
1688  {
1689  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
1690  "GESN supports OpChange, but must ignore these events for compatibility\n"));
1691  CLEAR_FLAG(header->SupportedEventClasses,
1693  }
1694  else
1695  {
1696  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
1697  "GESN supports OpChange\n"));
1698  }
1699  }
1700  info->Gesn.EventMask = header->SupportedEventClasses;
1701 
1702  //
1703  // realistically, we are only considering the following events:
1704  // EXTERNAL REQUEST - this is being tested for play/stop/etc.
1705  // MEDIA STATUS - autorun and ejection requests.
1706  // DEVICE BUSY - to allow us to predict when media will be ready.
1707  // therefore, we should not bother querying for the other,
1708  // unknown events. clear all but the above flags.
1709  //
1714 
1715 
1716  //
1717  // HACKHACK - REF #0001
1718  // Some devices will *never* report an event if we've also requested
1719  // that it report lower-priority events. this is due to a
1720  // misunderstanding in the specification wherein a "No Change" is
1721  // interpreted to be a real event. what should occur is that the
1722  // device should ignore "No Change" events when multiple event types
1723  // are requested unless there are no other events waiting. this
1724  // greatly reduces the number of requests that the host must send
1725  // to determine if an event has occurred. Since we must work on all
1726  // drives, default to enabling the hack until we find evidence of
1727  // proper firmware.
1728  //
1729  if (info->Gesn.EventMask == 0)
1730  {
1731  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
1732  "GESN supported, but not mask we care about (%x) for FDO %p\n",
1733  header->SupportedEventClasses,
1734  DeviceExtension->DeviceObject));
1735  // NOTE: the status is still status_sucess.
1736  break;
1737  }
1738  else if (CountOfSetBitsUChar(info->Gesn.EventMask) == 1)
1739  {
1740  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
1741  "GESN hack not required for FDO %p\n",
1742  DeviceExtension->DeviceObject));
1743  }
1744  else
1745  {
1746  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
1747  "GESN hack enabled for FDO %p\n",
1748  DeviceExtension->DeviceObject));
1749  info->Gesn.HackEventMask = 1;
1750  }
1751  }
1752  else
1753  {
1754  // i > 0; not the first time looping through, so interpret the results.
1755  status = GesnDataInterpret(DeviceExtension,
1756  (PVOID)info->Gesn.Buffer,
1757  &retryImmediately);
1758 
1759  if (!NT_SUCCESS(status))
1760  {
1761  // This drive does not support GESN correctly
1762  DeviceSetParameter( DeviceExtension,
1766  break;
1767  }
1768  }
1769  } // end 'for' loop of GESN requests....
1770  }
1771 
1772  if (NT_SUCCESS(status))
1773  {
1774  //
1775  // we can only use this if it can be relied upon for media changes,
1776  // since we are (by definition) no longer going to be polling via
1777  // a TEST_UNIT_READY irp, and drives will not report UNIT ATTENTION
1778  // for this command (although a filter driver, such as one for burning
1779  // cd's, might still fake those errors).
1780  //
1781  // since we also rely upon NOT_READY events to change the cursor
1782  // into a "wait" cursor; GESN is still more reliable than other
1783  // methods, and includes eject button requests, so we'll use it
1784  // without DEVICE_BUSY in Windows Vista.
1785  //
1786 
1787  if (TEST_FLAG(info->Gesn.EventMask, NOTIFICATION_MEDIA_STATUS_CLASS_MASK))
1788  {
1789  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
1790  "Enabling GESN support for WDFDEVICE %p\n",
1791  DeviceExtension->Device));
1792  info->Gesn.Supported = TRUE;
1793 
1794  DeviceSetParameter( DeviceExtension,
1798  }
1799  else
1800  {
1801  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
1802  "GESN available but not enabled for WDFDEVICE %p\n",
1803  DeviceExtension->Device));
1805  }
1806  }
1807 
1808  if (!NT_SUCCESS(status))
1809  {
1810  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN,
1811  "GESN support detection failed for WDFDEVICE %p with status %08x\n",
1812  DeviceExtension->Device, status));
1813 
1814  if (info->Gesn.Mdl)
1815  {
1816  PIRP irp = WdfRequestWdmGetIrp(info->MediaChangeRequest);
1817 
1818  IoFreeMdl(info->Gesn.Mdl);
1819  info->Gesn.Mdl = NULL;
1820  irp->MdlAddress = NULL;
1821  }
1822 
1823  FREE_POOL(info->Gesn.Buffer);
1824  info->Gesn.Supported = FALSE;
1825  info->Gesn.EventMask = 0;
1826  info->Gesn.BufferSize = 0;
1827  }
1828 
1829  return status;
1830 }
1831 
1832 
1834 NTSTATUS
1835 DeviceInitializeMediaChangeDetection(
1836  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
1837  )
1838 /*++
1839 
1840 Routine Description:
1841 
1842  This routine checks to see if it is safe to initialize MCN (the back end
1843  to autorun) for a given device. It will then check the device-type wide
1844  key "Autorun" in the service key (for legacy reasons), and then look in
1845  the device-specific key to potentially override that setting.
1846 
1847  If MCN is to be enabled, all neccessary structures and memory are
1848  allocated and initialized.
1849 
1850  This routine MUST be called only from the DeviceInit...() .
1851 
1852 Arguments:
1853 
1854  DeviceExtension - the device to initialize MCN for, if appropriate
1855 
1856 Return Value:
1857 
1858  NTSTATUS
1859 
1860 --*/
1861 {
1863 
1864  BOOLEAN disabled = FALSE;
1865  BOOLEAN instanceOverride;
1866 
1867  PAGED_CODE();
1868 
1869  // NOTE: This assumes that DeviceInitializeMediaChangeDetection is always
1870  // called in the context of the DeviceInitDevicePhase2. If called
1871  // after then this check will have already been made and the
1872  // once a second timer will not have been enabled.
1873 
1874  disabled = DeviceIsMediaChangeDisabledDueToHardwareLimitation(DeviceExtension);
1875 
1876  if (disabled)
1877  {
1878  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
1879  "DeviceInitializeMediaChangeDetection: Disabled due to hardware"
1880  "limitations for this device\n"));
1881  }
1882  else
1883  {
1884  // autorun should now be enabled by default for all media types.
1885  disabled = DeviceIsMediaChangeDisabledForClass(DeviceExtension);
1886 
1887  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
1888  "DeviceInitializeMediaChangeDetection: MCN is %s\n",
1889  (disabled ? "disabled" : "enabled")));
1890 
1891  status = DeviceMediaChangeDeviceInstanceOverride(DeviceExtension,
1892  &instanceOverride); // default value
1893 
1894  if (!NT_SUCCESS(status))
1895  {
1896  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
1897  "DeviceInitializeMediaChangeDetection: Instance using default\n"));
1898  }
1899  else
1900  {
1901  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
1902  "DeviceInitializeMediaChangeDetection: Instance override: %s MCN\n",
1903  (instanceOverride ? "Enabling" : "Disabling")));
1904  disabled = !instanceOverride;
1905  }
1906 
1907  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
1908  "DeviceInitializeMediaChangeDetection: Instance MCN is %s\n",
1909  (disabled ? "disabled" : "enabled")));
1910  }
1911 
1912  if (!disabled)
1913  {
1914  // if the drive is not a CDROM, allow the drive to sleep
1915  status = DeviceInitializeMcn(DeviceExtension, FALSE);
1916  }
1917 
1918  return status;
1919 } // end DeviceInitializeMediaChangeDetection()
1920 
1921 
1923 NTSTATUS
1924 DeviceMediaChangeDeviceInstanceOverride(
1925  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
1927  )
1928 /*++
1929 
1930 Routine Description:
1931 
1932  The user can override the global setting to enable or disable Autorun on a
1933  specific cdrom device via the control panel. This routine checks and/or
1934  sets this value.
1935 
1936 Arguments:
1937 
1938  DeviceExtension - the device to set/get the value for
1939 
1940  Enabled - TRUE (Autorun is enabled)
1941  FALSE (Autorun is disabled)
1942 Return Value:
1943  NTSTATUS
1944 
1945 --*/
1946 {
1948  WDFKEY deviceKey = NULL;
1949  WDFKEY subKey = NULL;
1950 
1951  UNICODE_STRING subkeyName;
1952  UNICODE_STRING enableMcnValueName;
1953  UNICODE_STRING disableMcnValueName;
1954  ULONG alwaysEnable = 0;
1955  ULONG alwaysDisable = 0;
1956 
1957  PAGED_CODE();
1958 
1959  status = WdfDeviceOpenRegistryKey(DeviceExtension->Device,
1963  &deviceKey);
1964  if (!NT_SUCCESS(status))
1965  {
1966  // this can occur when a new device is added to the system
1967  // this is due to cdrom.sys being an 'essential' driver
1968  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
1969  "DeviceMediaChangeDeviceInstanceOverride: "
1970  "Could not open device registry key [%lx]\n", status));
1971  }
1972  else
1973  {
1975 
1976  status = WdfRegistryOpenKey(deviceKey,
1977  &subkeyName,
1978  KEY_READ,
1980  &subKey);
1981  }
1982 
1983  if (!NT_SUCCESS(status))
1984  {
1985  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
1986  "DeviceMediaChangeDeviceInstanceOverride: "
1987  "subkey could not be created. %lx\n", status));
1988  }
1989  else
1990  {
1991  // Default to not changing autorun behavior, based upon setting
1992  // registryValue to zero.
1995 
1996  // Ignore failures on reading of subkeys
1997  (VOID) WdfRegistryQueryULong(subKey,
1998  &enableMcnValueName,
1999  &alwaysEnable);
2000  (VOID) WdfRegistryQueryULong(subKey,
2001  &disableMcnValueName,
2002  &alwaysDisable);
2003  }
2004 
2005  // set return value and cleanup
2006 
2007  if (subKey != NULL)
2008  {
2009  WdfRegistryClose(subKey);
2010  }
2011 
2012  if (deviceKey != NULL)
2013  {
2014  WdfRegistryClose(deviceKey);
2015  }
2016 
2017  if (alwaysEnable && alwaysDisable)
2018  {
2019  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2020  "DeviceMediaChangeDeviceInstanceOverride: %s selected\n",
2021  "Both Enable and Disable set -- DISABLE"));
2024  *Enabled = FALSE;
2025  }
2026  else if (alwaysDisable)
2027  {
2028  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2029  "DeviceMediaChangeDeviceInstanceOverride: %s selected\n",
2030  "DISABLE"));
2033  *Enabled = FALSE;
2034  }
2035  else if (alwaysEnable)
2036  {
2037  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2038  "DeviceMediaChangeDeviceInstanceOverride: %s selected\n",
2039  "ENABLE"));
2042  *Enabled = TRUE;
2043  }
2044  else
2045  {
2046  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2047  "DeviceMediaChangeDeviceInstanceOverride: %s selected\n",
2048  "DEFAULT"));
2050  }
2051 
2052  return status;
2053 } // end DeviceMediaChangeDeviceInstanceOverride()
2054 
2055 
2056 NTSTATUS
2057 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
2065  )
2066 /*++
2067 
2068 Routine Description:
2069 
2070  This callback for a registry SZ or MULTI_SZ is called once for each
2071  SZ in the value. It will attempt to match the data with the
2072  UNICODE_STRING passed in as Context, and modify EntryContext if a
2073  match is found. Written for ClasspCheckRegistryForMediaChangeCompletion
2074 
2075 Arguments:
2076 
2077  ValueName - name of the key that was opened
2078  ValueType - type of data stored in the value (REG_SZ for this routine)
2079  ValueData - data in the registry, in this case a wide string
2080  ValueLength - length of the data including the terminating null
2081  Context - unicode string to compare against ValueData
2082  EntryContext - should be initialized to 0, will be set to 1 if match found
2083 
2084 Return Value:
2085 
2086  STATUS_SUCCESS
2087  EntryContext will be 1 if found
2088 
2089 --*/
2090 {
2091  PULONG valueFound;
2092  PUNICODE_STRING deviceString;
2093  PWSTR keyValue;
2094 
2095  PAGED_CODE();
2096 
2098 
2099  if ((Context == NULL) || (EntryContext == NULL))
2100  {
2101  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN,
2102  "DeviceMediaChangeRegistryCallBack: NULL context should never be passed to registry call-back!\n"));
2103 
2104  return STATUS_SUCCESS;
2105  }
2106 
2107  // if we have already set the value to true, exit
2108  valueFound = EntryContext;
2109  if ((*valueFound) != 0)
2110  {
2111  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2112  "DeviceMediaChangeRegistryCallBack: already set to true\n"));
2113  return STATUS_SUCCESS;
2114  }
2115 
2116  if (ValueLength == sizeof(WCHAR))
2117  {
2118  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN,
2119  "DeviceMediaChangeRegistryCallBack: NULL string should never be passed to registry call-back!\n"));
2120  return STATUS_SUCCESS;
2121  }
2122 
2123  // if the data is not a terminated string, exit
2124  if (ValueType != REG_SZ)
2125  {
2126  return STATUS_SUCCESS;
2127  }
2128 
2129  deviceString = Context;
2130  keyValue = ValueData;
2131  ValueLength -= sizeof(WCHAR); // ignore the null character
2132 
2133  // do not compare more memory than is in deviceString
2134  if (ValueLength > deviceString->Length)
2135  {
2136  ValueLength = deviceString->Length;
2137  }
2138 
2139  if (keyValue == NULL)
2140  {
2141  return STATUS_SUCCESS;
2142  }
2143 
2144  // if the strings match, disable autorun
2145  if (RtlCompareMemory(deviceString->Buffer, keyValue, ValueLength) == ValueLength)
2146  {
2147  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_MCN, "DeviceMediaChangeRegistryCallBack: Match found\n"));
2148  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_MCN, "DeviceMediaChangeRegistryCallBack: DeviceString at %p\n",
2149  deviceString->Buffer));
2150  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_MCN,
2151  "DeviceMediaChangeRegistryCallBack: KeyValue at %p\n",
2152  keyValue));
2153  (*valueFound) = TRUE;
2154  }
2155 
2156  return STATUS_SUCCESS;
2157 } // end DeviceMediaChangeRegistryCallBack()
2158 
2159 
2161 BOOLEAN
2162 DeviceIsMediaChangeDisabledDueToHardwareLimitation(
2163  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
2164  )
2165 /*++
2166 
2167 Routine Description:
2168 
2169  The key AutoRunAlwaysDisable contains a MULTI_SZ of hardware IDs for
2170  which to never enable MediaChangeNotification.
2171 
2172  The user can override the global setting to enable or disable Autorun on a
2173  specific cdrom device via the control panel.
2174 
2175  NOTE: It's intended that not use WdfRegistryQueryMultiString in this funciton,
2176  as it's much more complicated.(needs WDFCOLLECTION, WDFSTRING other than
2177  UNICODE_STRING)
2178 
2179 Arguments:
2180 
2181  FdoExtension -
2182  RegistryPath - pointer to the unicode string inside
2183  ...\CurrentControlSet\Services\Cdrom
2184 
2185 Return Value:
2186 
2187  TRUE - no autorun.
2188  FALSE - Autorun may be enabled
2189 
2190 --*/
2191 {
2192  NTSTATUS status;
2193 
2194  PSTORAGE_DEVICE_DESCRIPTOR deviceDescriptor = DeviceExtension->DeviceDescriptor;
2195  WDFKEY wdfKey;
2196  HANDLE serviceKey = NULL;
2197  RTL_QUERY_REGISTRY_TABLE parameters[2] = {0};
2198 
2199  UNICODE_STRING deviceUnicodeString = {0};
2200  ANSI_STRING deviceString = {0};
2201  ULONG mediaChangeNotificationDisabled = 0;
2202 
2203  PAGED_CODE();
2204 
2205  // open the service key.
2206  status = WdfDriverOpenParametersRegistryKey(WdfGetDriver(),
2209  &wdfKey);
2210 
2211  if(!NT_SUCCESS(status))
2212  {
2213  // NT_ASSERT(FALSE); __REACTOS__ : allow to fail (for 1st stage setup)
2214 
2215  // always take the safe path. if we can't open the service key, disable autorun
2216  return TRUE;
2217  }
2218 
2219  if(NT_SUCCESS(status))
2220  {
2221  // Determine if drive is in a list of those requiring
2222  // autorun to be disabled. this is stored in a REG_MULTI_SZ
2223  // named AutoRunAlwaysDisable. this is required as some autochangers
2224  // must load the disc to reply to ChkVerify request, causing them
2225  // to cycle discs continuously.
2226 
2227  PWSTR nullMultiSz;
2228  PUCHAR vendorId = NULL;
2229  PUCHAR productId = NULL;
2230  PUCHAR revisionId = NULL;
2231  size_t length;
2232  size_t offset;
2233 
2234  deviceString.Buffer = NULL;
2235  deviceUnicodeString.Buffer = NULL;
2236 
2237  serviceKey = WdfRegistryWdmGetHandle(wdfKey);
2238 
2239  // there may be nothing to check against
2240  if ((deviceDescriptor->VendorIdOffset == 0) &&
2241  (deviceDescriptor->ProductIdOffset == 0))
2242  {
2243  // no valid data in device extension.
2245  }
2246 
2247  // build deviceString using VendorId, Model and Revision.
2248  // this string will be used to checked if it's one of devices in registry disable list.
2249  if (NT_SUCCESS(status))
2250  {
2251  length = 0;
2252 
2253  if (deviceDescriptor->VendorIdOffset == 0)
2254  {
2255  vendorId = NULL;
2256  }
2257  else
2258  {
2259  vendorId = (PUCHAR) deviceDescriptor + deviceDescriptor->VendorIdOffset;
2260  length = strlen((LPCSTR)vendorId);
2261  }
2262 
2263  if ( deviceDescriptor->ProductIdOffset == 0 )
2264  {
2265  productId = NULL;
2266  }
2267  else
2268  {
2269  productId = (PUCHAR) deviceDescriptor + deviceDescriptor->ProductIdOffset;
2270  length += strlen((LPCSTR)productId);
2271  }
2272 
2273  if ( deviceDescriptor->ProductRevisionOffset == 0 )
2274  {
2275  revisionId = NULL;
2276  }
2277  else
2278  {
2279  revisionId = (PUCHAR) deviceDescriptor + deviceDescriptor->ProductRevisionOffset;
2280  length += strlen((LPCSTR)revisionId);
2281  }
2282 
2283  // allocate a buffer for the string
2284  deviceString.Length = (USHORT)( length );
2285  deviceString.MaximumLength = deviceString.Length + 1;
2286  deviceString.Buffer = (PCHAR)ExAllocatePoolWithTag( NonPagedPoolNx,
2287  deviceString.MaximumLength,
2289  );
2290  if (deviceString.Buffer == NULL)
2291  {
2292  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2293  "DeviceIsMediaChangeDisabledDueToHardwareLimitation: Unable to alloc string buffer\n" ));
2295  }
2296  }
2297 
2298  if (NT_SUCCESS(status))
2299  {
2300  // copy strings to the buffer
2301  offset = 0;
2302 
2303  if (vendorId != NULL)
2304  {
2305  RtlCopyMemory(deviceString.Buffer + offset,
2306  vendorId,
2307  strlen((LPCSTR)vendorId));
2308  offset += strlen((LPCSTR)vendorId);
2309  }
2310 
2311  if ( productId != NULL )
2312  {
2313  RtlCopyMemory(deviceString.Buffer + offset,
2314  productId,
2315  strlen((LPCSTR)productId));
2316  offset += strlen((LPCSTR)productId);
2317  }
2318  if ( revisionId != NULL )
2319  {
2320  RtlCopyMemory(deviceString.Buffer + offset,
2321  revisionId,
2322  strlen((LPCSTR)revisionId));
2323  offset += strlen((LPCSTR)revisionId);
2324  }
2325 
2326  NT_ASSERT(offset == deviceString.Length);
2327 
2328  #pragma warning(suppress:6386) // Not an issue as deviceString.Buffer is of size deviceString.MaximumLength, which is equal to (deviceString.Length + 1)
2329  deviceString.Buffer[deviceString.Length] = '\0'; // Null-terminated
2330 
2331  // convert to unicode as registry deals with unicode strings
2332  status = RtlAnsiStringToUnicodeString( &deviceUnicodeString,
2333  &deviceString,
2334  TRUE
2335  );
2336  if (!NT_SUCCESS(status))
2337  {
2338  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2339  "DeviceIsMediaChangeDisabledDueToHardwareLimitation: cannot convert "
2340  "to unicode %lx\n", status));
2341  }
2342  }
2343 
2344  if (NT_SUCCESS(status))
2345  {
2346  // query the value, setting valueFound to true if found
2347  nullMultiSz = L"\0";
2349  parameters[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
2350  parameters[0].Name = L"AutoRunAlwaysDisable";
2351  parameters[0].EntryContext = &mediaChangeNotificationDisabled;
2352  parameters[0].DefaultType = REG_MULTI_SZ;
2353  parameters[0].DefaultData = nullMultiSz;
2354  parameters[0].DefaultLength = 0;
2355 
2357  serviceKey,
2358  parameters,
2359  &deviceUnicodeString,
2360  NULL);
2361  UNREFERENCED_PARAMETER(status); //defensive coding, avoid PREFAST warning.
2362  }
2363  }
2364 
2365  // Cleanup
2366  {
2367 
2368  FREE_POOL( deviceString.Buffer );
2369  if (deviceUnicodeString.Buffer != NULL)
2370  {
2371  RtlFreeUnicodeString( &deviceUnicodeString );
2372  }
2373 
2374  // handle serviceKey will be closed by framework while it closes registry key.
2375  WdfRegistryClose(wdfKey);
2376  }
2377 
2378  if (mediaChangeNotificationDisabled > 0)
2379  {
2380  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2381  "DeviceIsMediaChangeDisabledDueToHardwareLimitation: Device is on MCN disable list\n"));
2382  }
2383 
2384  return (mediaChangeNotificationDisabled > 0);
2385 
2386 } // end DeviceIsMediaChangeDisabledDueToHardwareLimitation()
2387 
2388 
2390 BOOLEAN
2391 DeviceIsMediaChangeDisabledForClass(
2392  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
2393  )
2394 /*++
2395 
2396 Routine Description:
2397 
2398  The user must specify that AutoPlay is to run on the platform
2399  by setting the registry value HKEY_LOCAL_MACHINE\System\CurrentControlSet\
2400  Services<SERVICE>\Autorun:REG_DWORD:1.
2401 
2402  The user can override the global setting to enable or disable Autorun on a
2403  specific cdrom device via the control panel.
2404 
2405 Arguments:
2406 
2407  DeviceExtension - device extension
2408 
2409 Return Value:
2410 
2411  TRUE - Autorun is disabled for this class
2412  FALSE - Autorun is enabled for this class
2413 
2414 --*/
2415 {
2416  NTSTATUS status;
2417  WDFKEY serviceKey = NULL;
2418  WDFKEY parametersKey = NULL;
2419 
2420  UNICODE_STRING parameterKeyName;
2421  UNICODE_STRING valueName;
2422 
2423  // Default to ENABLING MediaChangeNotification (!)
2424  ULONG mcnRegistryValue = 1;
2425 
2426  PAGED_CODE();
2427 
2428  // open the service key.
2429  status = WdfDriverOpenParametersRegistryKey(WdfGetDriver(),
2432  &serviceKey);
2433  if(!NT_SUCCESS(status))
2434  {
2435  // return the default value, which is the inverse of the registry setting default
2436  // since this routine asks if it's disabled
2437  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2438  "DeviceIsMediaChangeDisabledForClass: Defaulting to %s\n",
2439  (mcnRegistryValue ? "Enabled" : "Disabled")));
2440  return (BOOLEAN)(mcnRegistryValue == 0);
2441  }
2442  else
2443  {
2444  // Open the parameters key (if any) beneath the services key.
2445  RtlInitUnicodeString(&parameterKeyName, L"Parameters");
2446 
2447  status = WdfRegistryOpenKey(serviceKey,
2448  &parameterKeyName,
2449  KEY_READ,
2451  &parametersKey);
2452  }
2453 
2454  if (!NT_SUCCESS(status))
2455  {
2456  parametersKey = NULL;
2457  }
2458 
2459  RtlInitUnicodeString(&valueName, L"Autorun");
2460  // ignore failures
2461  status = WdfRegistryQueryULong(serviceKey,
2462  &valueName,
2463  &mcnRegistryValue);
2464 
2465  if (NT_SUCCESS(status))
2466  {
2467  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_MCN,
2468  "DeviceIsMediaChangeDisabledForClass: <Service>/Autorun flag = %d\n",
2469  mcnRegistryValue));
2470  }
2471 
2472  if (parametersKey != NULL)
2473  {
2474  status = WdfRegistryQueryULong(parametersKey,
2475  &valueName,
2476  &mcnRegistryValue);
2477 
2478  if (NT_SUCCESS(status))
2479  {
2480  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_MCN,
2481  "DeviceIsMediaChangeDisabledForClass: <Service>/Parameters/Autorun flag = %d\n",
2482  mcnRegistryValue));
2483  }
2484 
2485  WdfRegistryClose(parametersKey);
2486  }
2487 
2488  WdfRegistryClose(serviceKey);
2489 
2490  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2491  "DeviceIsMediaChangeDisabledForClass: Autoplay for device %p is %s\n",
2492  DeviceExtension->DeviceObject,
2493  (mcnRegistryValue ? "on" : "off")
2494  ));
2495 
2496  // return if it is _disabled_, which is the
2497  // inverse of the registry setting
2498 
2499  return (BOOLEAN)(!mcnRegistryValue);
2500 } // end DeviceIsMediaChangeDisabledForClass()
2501 
2502 
2504 VOID
2505 DeviceEnableMediaChangeDetection(
2506  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
2509  )
2510 /*++
2511 
2512 Routine Description:
2513 
2514  When the disable count decrease to 0, enable the MCN
2515 
2516 Arguments:
2517 
2518  DeviceExtension - the device context
2519 
2520  FileObjectContext - the file object context
2521 
2522  IgnorePreviousMediaChanges - ignore all previous media changes
2523 
2524 Return Value:
2525  None.
2526 
2527 --*/
2528 {
2529  PMEDIA_CHANGE_DETECTION_INFO info = DeviceExtension->MediaChangeDetectionInfo;
2530  LONG oldCount;
2531 
2532  PAGED_CODE();
2533 
2534  if (FileObjectContext)
2535  {
2537  }
2538 
2539  if (info == NULL)
2540  {
2541  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2542  "DeviceEnableMediaChangeDetection: not initialized\n"));
2543  return;
2544  }
2545 
2546  (VOID) KeWaitForMutexObject(&info->MediaChangeMutex,
2547  UserRequest,
2548  KernelMode,
2549  FALSE,
2550  NULL);
2551 
2552  oldCount = --info->MediaChangeDetectionDisableCount;
2553 
2554  NT_ASSERT(oldCount >= 0);
2555 
2556  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_MCN,
2557  "DeviceEnableMediaChangeDetection: Disable count reduced to %d - \n",
2558  info->MediaChangeDetectionDisableCount));
2559 
2560  if (oldCount == 0)
2561  {
2563  {
2564  info->LastReportedMediaDetectionState = info->LastKnownMediaDetectionState;
2565  }
2566 
2567  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "MCN is enabled\n"));
2568  }
2569  else
2570  {
2571  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_MCN, "MCD still disabled\n"));
2572  }
2573 
2574  // Let something else run.
2575  KeReleaseMutex(&info->MediaChangeMutex, FALSE);
2576 
2577  return;
2578 } // end DeviceEnableMediaChangeDetection()
2579 
2580 
2582 VOID
2583 DeviceDisableMediaChangeDetection(
2584  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
2586  )
2587 /*++
2588 
2589 Routine Description:
2590 
2591  Increase the disable count.
2592 
2593 Arguments:
2594 
2595  DeviceExtension - the device context
2596 
2597  FileObjectContext - the file object context
2598 
2599 Return Value:
2600  None.
2601 
2602 --*/
2603 {
2604  PMEDIA_CHANGE_DETECTION_INFO info = DeviceExtension->MediaChangeDetectionInfo;
2605 
2606  PAGED_CODE();
2607 
2608  if (FileObjectContext)
2609  {
2611  }
2612 
2613  if (info == NULL)
2614  {
2615  return;
2616  }
2617 
2618  (VOID) KeWaitForMutexObject(&info->MediaChangeMutex,
2619  UserRequest,
2620  KernelMode,
2621  FALSE,
2622  NULL);
2623 
2624  info->MediaChangeDetectionDisableCount++;
2625 
2626  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_MCN,
2627  "DisableMediaChangeDetection: disable count is %d\n",
2628  info->MediaChangeDetectionDisableCount));
2629 
2630  KeReleaseMutex(&info->MediaChangeMutex, FALSE);
2631 
2632  return;
2633 } // end DeviceDisableMediaChangeDetection()
2634 
2635 
2637 VOID
2638 DeviceReleaseMcnResources(
2639  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
2640  )
2641 /*++
2642 
2643 Routine Description:
2644 
2645  This routine will cleanup any resources allocated for MCN. It is called
2646  by classpnp during remove device, and therefore is not typically required
2647  by external drivers.
2648 
2649 Arguments:
2650 
2651  DeviceExtension - the device context
2652 
2653 Return Value:
2654  None.
2655 
2656 --*/
2657 {
2658  PMEDIA_CHANGE_DETECTION_INFO info = DeviceExtension->MediaChangeDetectionInfo;
2659 
2660  PAGED_CODE()
2661 
2662  if(info == NULL)
2663  {
2664  return;
2665  }
2666 
2667  if (info->Gesn.Mdl)
2668  {
2669  PIRP irp = WdfRequestWdmGetIrp(info->MediaChangeRequest);
2670  IoFreeMdl(info->Gesn.Mdl);
2671  irp->MdlAddress = NULL;
2672  }
2673  IoFreeIrp(info->MediaChangeSyncIrp);
2674  FREE_POOL(info->Gesn.Buffer);
2675  FREE_POOL(info->SenseBuffer);
2676 
2677  if (info->DisplayStateCallbackHandle)
2678  {
2679  PoUnregisterPowerSettingCallback(info->DisplayStateCallbackHandle);
2680  info->DisplayStateCallbackHandle = NULL;
2681  }
2682 
2683  FREE_POOL(info);
2684 
2685  DeviceExtension->MediaChangeDetectionInfo = NULL;
2686 
2687  return;
2688 } // end DeviceReleaseMcnResources()
2689 
2690 
2691 IO_COMPLETION_ROUTINE RequestMcnSyncIrpCompletion;
2692 
2693 NTSTATUS
2694 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
2697  _In_ PIRP Irp,
2698  _In_reads_opt_(_Inexpressible_("varies")) PVOID Context
2699  )
2700 /*++
2701 
2702 Routine Description:
2703 
2704  The MCN work finishes, reset the fields to allow another MCN request
2705  be scheduled.
2706 
2707 Arguments:
2708 
2709  DeviceObject - device that the completion routine fires on.
2710 
2711  Irp - The irp to be completed.
2712 
2713  Context - IRP context
2714 
2715 Return Value:
2716  NTSTATUS
2717 
2718 --*/
2719 {
2720  PCDROM_DEVICE_EXTENSION DeviceExtension = NULL;
2722 
2723  if (Context == NULL)
2724  {
2725  // this will never happen, but code must be there to prevent OACR warnings.
2727  }
2728 
2729  DeviceExtension = (PCDROM_DEVICE_EXTENSION) Context;
2730  info = DeviceExtension->MediaChangeDetectionInfo;
2731 
2732 #ifndef DEBUG
2734 #endif
2736 
2737  NT_ASSERT(Irp == info->MediaChangeSyncIrp);
2738 
2739  IoReuseIrp(info->MediaChangeSyncIrp, STATUS_NOT_SUPPORTED);
2740 
2741  // reset the value to let timer routine be able to send the next request.
2742  InterlockedCompareExchange((PLONG)&(info->MediaChangeRequestInUse), 0, 1);
2743 
2745 }
2746 
2747 
2748 VOID
2750  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
2751  )
2752 /*++
2753 
2754 Routine Description:
2755 
2756  setup the MCN synchronization irp.
2757 
2758 Arguments:
2759 
2760  DeviceExtension - the device context
2761 
2762 Return Value:
2763  None
2764 
2765 --*/
2766 {
2767  PIRP irp = NULL;
2768  PIO_STACK_LOCATION irpStack = NULL;
2769  PIO_STACK_LOCATION nextIrpStack = NULL;
2770 
2771  irp = DeviceExtension->MediaChangeDetectionInfo->MediaChangeSyncIrp;
2772  NT_ASSERT(irp != NULL);
2773 
2774  //
2775  // For the driver that creates an IRP, there is no 'current' stack location.
2776  // Step down one IRP stack location so that the extra top one
2777  // becomes our 'current' one.
2778  //
2780 
2781  /*
2782  * Cache our device object in the extra top IRP stack location
2783  * so we have it in our completion routine.
2784  */
2785  irpStack = IoGetCurrentIrpStackLocation(irp);
2786  irpStack->DeviceObject = DeviceExtension->DeviceObject;
2787 
2788  //
2789  // If the irp is sent down when the volume needs to be
2790  // verified, CdRomUpdateGeometryCompletion won't complete
2791  // it since it's not associated with a thread. Marking
2792  // it to override the verify causes it always be sent
2793  // to the port driver
2794  //
2795  nextIrpStack = IoGetNextIrpStackLocation(irp);
2796 
2797  SET_FLAG(nextIrpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME);
2798 
2799  nextIrpStack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
2800  // pick up this IOCTL code as it's not normaly seen for CD/DVD drive and does not require input.
2801  // set other fields to make this IOCTL recognizable by CDROM.SYS
2802  nextIrpStack->Parameters.Others.Argument1 = RequestSetupMcnSyncIrp;
2803  nextIrpStack->Parameters.Others.Argument2 = RequestSetupMcnSyncIrp;
2804  nextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_MCN_SYNC_FAKE_IOCTL; //Argument3.
2805  nextIrpStack->Parameters.Others.Argument4 = RequestSetupMcnSyncIrp;
2806 
2809  DeviceExtension,
2810  TRUE,
2811  TRUE,
2812  TRUE);
2813 
2814  return;
2815 }
2816 
2817 
2818 VOID
2819 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
2821  _In_ WDFTIMER Timer
2822  )
2823 /*++
2824 
2825 Routine Description:
2826 
2827  This routine setup a sync irp and send it to the serial queue.
2828  Serial queue will process MCN when receive this sync irp.
2829 
2830 Arguments:
2831 
2832  Timer - the timer object that fires.
2833 
2834 Return Value:
2835  None
2836 
2837 --*/
2838 {
2839  PCDROM_DEVICE_EXTENSION deviceExtension = NULL;
2840  size_t dataLength = 0;
2841 
2842  deviceExtension = WdfObjectGetTypedContext(WdfTimerGetParentObject(Timer), CDROM_DEVICE_EXTENSION);
2843 
2844  (void) RequestHandleEventNotification(deviceExtension, NULL, NULL, &dataLength);
2845 
2846  return;
2847 } // end DeviceMainTimerTickHandler()
2848 
2849 
2851 NTSTATUS
2852 DeviceEnableMainTimer(
2853  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
2854  )
2855 /*++
2856 
2857 Routine Description:
2858 
2859  This routine will allocate timer related resources on the first time call.
2860  Start the timer.
2861 
2862 Arguments:
2863 
2864  DeviceExtension - the device context
2865 
2866 Return Value:
2867  NTSTATUS
2868 
2869 --*/
2870 {
2872 
2873  if ((DeviceExtension->MediaChangeDetectionInfo == NULL) ||
2874  (DeviceExtension->MediaChangeDetectionInfo->AsynchronousNotificationSupported != FALSE))
2875  {
2876  // Asynchronous Notification is enabled, timer not needed.
2877  return status;
2878  }
2879 
2880  if (DeviceExtension->MainTimer == NULL)
2881  {
2882  //create main timer object.
2883  WDF_TIMER_CONFIG timerConfig;
2884  WDF_OBJECT_ATTRIBUTES timerAttributes;
2885 
2887 
2888  // Polling frequently on virtual optical devices created by Hyper-V will
2889  // cause a significant perf / power hit. These devices need to be polled
2890  // less frequently for device state changes.
2891  if (TEST_FLAG(DeviceExtension->DeviceAdditionalData.HackFlags, CDROM_HACK_MSFT_VIRTUAL_ODD))
2892  {
2893  timerConfig.Period = 2000; // 2 seconds, in milliseconds.
2894  }
2895  else
2896  {
2897  timerConfig.Period = 1000; // 1 second, in milliseconds.
2898  }
2899 
2900  timerConfig.TolerableDelay = 500; // 0.5 seconds, in milliseconds
2901 
2902  //Set the autoSerialization to FALSE, as the parent device's
2903  //execute level is WdfExecutionLevelPassive.
2904  timerConfig.AutomaticSerialization = FALSE;
2905 
2906  WDF_OBJECT_ATTRIBUTES_INIT(&timerAttributes);
2907  timerAttributes.ParentObject = DeviceExtension->Device;
2909 
2910  status = WdfTimerCreate(&timerConfig,
2911  &timerAttributes,
2912  &DeviceExtension->MainTimer);
2913  }
2914 
2915  if (NT_SUCCESS(status))
2916  {
2917  WdfTimerStart(DeviceExtension->MainTimer,WDF_REL_TIMEOUT_IN_MS(100));
2918 
2919  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2920  "DeviceEnableMainTimer: Once a second timer enabled for WDFDEVICE %p\n",
2921  DeviceExtension->Device));
2922  }
2923  else
2924  {
2925  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2926  "DeviceEnableMainTimer: WDFDEVICE %p, Status %lx initializing timer\n",
2927  DeviceExtension->Device, status));
2928  }
2929 
2930  return status;
2931 } // end DeviceEnableMainTimer()
2932 
2933 
2935 VOID
2936 DeviceDisableMainTimer(
2937  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
2938  )
2939 /*++
2940 
2941 Routine Description:
2942 
2943  stop the timer.
2944 
2945 Arguments:
2946 
2947  DeviceExtension - device context
2948 
2949 Return Value:
2950  None
2951 
2952 --*/
2953 {
2954  PAGED_CODE();
2955 
2956  if ((DeviceExtension->MediaChangeDetectionInfo == NULL) ||
2957  (DeviceExtension->MediaChangeDetectionInfo->AsynchronousNotificationSupported != FALSE))
2958  {
2959  // Asynchronous Notification is enabled, timer not needed.
2960  return;
2961  }
2962 
2963  if (DeviceExtension->MainTimer != NULL)
2964  {
2965  //
2966  // we are only going to stop the actual timer in remove device routine.
2967  // it is the responsibility of the code within the timer routine to
2968  // check if the device is removed and not processing io for the final
2969  // call.
2970  // this keeps the code clean and prevents lots of bugs.
2971  //
2972  WdfTimerStop(DeviceExtension->MainTimer,TRUE);
2973 
2974  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2975  "DeviceDisableMainTimer: Once a second timer disabled for device %p\n",
2976  DeviceExtension->Device));
2977  }
2978  else
2979  {
2980  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN,
2981  "DeviceDisableMainTimer: Timer never enabled\n"));
2982  }
2983 
2984  return;
2985 } // end DeviceDisableMainTimer()
2986 
2987 
2989 NTSTATUS
2990 RequestHandleMcnControl(
2991  _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
2992  _In_ WDFREQUEST Request,
2993  _Out_ size_t * DataLength
2994  )
2995 /*++
2996 
2997 Routine Description:
2998 
2999  This routine handles the process of IOCTL_STORAGE_MCN_CONTROL
3000 
3001 Arguments:
3002 
3003  DeviceExtension - device context
3004 
3005  Request - request object
3006 
3007  RequestParameters - request parameters
3008 
3009  DataLength - data transferred
3010 
3011 Return Value:
3012  NTSTATUS
3013 
3014 --*/
3015 {
3017  WDFFILEOBJECT fileObject = NULL;
3018  PFILE_OBJECT_CONTEXT fileObjectContext = NULL;
3019  PPREVENT_MEDIA_REMOVAL mediaRemoval = NULL;
3020 
3021  PAGED_CODE();
3022 
3023  *DataLength = 0;
3024 
3025  status = WdfRequestRetrieveInputBuffer(Request,
3026  sizeof(PREVENT_MEDIA_REMOVAL),
3027  &mediaRemoval,
3028  NULL);
3029 
3030  if (NT_SUCCESS(status))
3031  {
3032  fileObject = WdfRequestGetFileObject(Request);
3033 
3034  // Check to make sure we have a file object extension to keep track of this
3035  // request. If not we'll fail it before synchronizing.
3036  if (fileObject != NULL)
3037  {
3038  fileObjectContext = FileObjectGetContext(fileObject);
3039  }
3040 
3041  if ((fileObjectContext == NULL) &&
3042  (WdfRequestGetRequestorMode(Request) == KernelMode))
3043  {
3044  fileObjectContext = &DeviceExtension->KernelModeMcnContext;
3045  }
3046 
3047  if (fileObjectContext == NULL)
3048  {
3049  // This handle isn't setup correctly. We can't let the
3050  // operation go.
3052  }
3053  }
3054 
3055  if (NT_SUCCESS(status))
3056  {
3057  if (mediaRemoval->PreventMediaRemoval)
3058  {
3059  // This is a lock command. Reissue the command in case bus or
3060  // device was reset and the lock was cleared.
3061  DeviceDisableMediaChangeDetection(DeviceExtension, fileObjectContext);
3062  }
3063  else
3064  {
3065  if (fileObjectContext->McnDisableCount == 0)
3066  {
3068  }
3069  else
3070  {
3071  DeviceEnableMediaChangeDetection(DeviceExtension, fileObjectContext, TRUE);
3072  }
3073  }
3074  }
3075 
3076  return status;
3077 } // end RequestHandleMcnControl()
3078 
3079 #pragma warning(pop) // un-sets any local warning changes
3080 
#define KeQuerySystemTime(t)
Definition: env_spec_w32.h:570
BOOLEAN AutomaticSerialization
Definition: wdftimer.h:90
#define NOTIFICATION_NO_CLASS_EVENTS
Definition: scsi.h:42
#define SRB_STATUS_BUS_RESET
Definition: srb.h:345
BOOLEAN AsynchronousNotificationSupported
Definition: cdromp.h:178
UCHAR SenseKey
Definition: cdrw_hw.h:1167
return STATUS_NOT_SUPPORTED
struct _NOTIFICATION_OPERATIONAL_STATUS * PNOTIFICATION_OPERATIONAL_STATUS
#define FDO_HACK_GESN_IGNORE_OPCHANGE
Definition: cdromp.h:136
#define LOADING_MECHANISM_CADDY
Definition: scsi.h:971
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
ULONG SrbFlags
Definition: srb.h:252
struct png_info_def **typedef void(__cdecl typeof(png_destroy_read_struct))(struct png_struct_def **
Definition: typeof.h:49
#define _In_opt_
Definition: ms_sal.h:309
FORCEINLINE VOID WDF_WORKITEM_CONFIG_INIT(_Out_ PWDF_WORKITEM_CONFIG Config, _In_ PFN_WDF_WORKITEM EvtWorkItemFunc)
Definition: wdfworkitem.h:85
#define SCSIOP_GET_EVENT_STATUS
Definition: cdrw_hw.h:934
#define _Inout_
Definition: ms_sal.h:378
_In_ BOOLEAN UseGesn
Definition: cdrom.h:1363
PVOID OriginalRequest
Definition: srb.h:258
NTSTATUS NTAPI DeviceMediaChangeRegistryCallBack(_In_z_ PWSTR ValueName, _In_ ULONG ValueType, _In_reads_bytes_opt_(ValueLength) PVOID ValueData, _In_ ULONG ValueLength, _In_opt_ PVOID Context, _In_opt_ PVOID EntryContext)
Definition: autorun.c:2058
UCHAR Cdb[16]
Definition: srb.h:271
NTSYSAPI NTSTATUS WINAPI RtlQueryRegistryValues(ULONG, PCWSTR, PRTL_QUERY_REGISTRY_TABLE, PVOID, PVOID)
#define KeWaitForMutexObject
Definition: kefuncs.h:555
VOID NTAPI IoReuseIrp(IN OUT PIRP Irp, IN NTSTATUS Status)
Definition: irp.c:1971
#define STATUS_DATA_OVERRUN
Definition: udferr_usr.h:152
#define STATUS_MORE_PROCESSING_REQUIRED
Definition: shellext.h:68
#define _Out_
Definition: ms_sal.h:345
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
#define NOTIFICATION_MEDIA_STATUS_CLASS_MASK
Definition: scsi.h:37
#define SRB_STATUS_AUTOSENSE_VALID
Definition: srb.h:379
#define PLUGPLAY_REGKEY_DEVICE
Definition: iofuncs.h:2786
#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 UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
PVOID DataBuffer
Definition: srb.h:255
uint16_t * PWSTR
Definition: typedefs.h:56
#define NOTIFICATION_EXTERNAL_REQUEST_CLASS_MASK
Definition: scsi.h:36
unsigned char * PUCHAR
Definition: retypes.h:3
#define NOTIFICATION_EXTERNAL_EVENT_BUTTON_DOWN
Definition: scsi.h:76
ULONG DataTransferLength
Definition: srb.h:253
#define NOTIFICATION_MEDIA_EVENT_NEW_MEDIA
Definition: scsi.h:95
VOID NTAPI MmBuildMdlForNonPagedPool(IN PMDL Mdl)
Definition: mdlsup.c:415
#define FDO_HACK_NO_ASYNCHRONOUS_NOTIFICATION
Definition: cdromp.h:138
Definition: cdrw_hw.h:28
LONG NTSTATUS
Definition: precomp.h:26
#define SCSIOP_TEST_UNIT_READY
Definition: cdrw_hw.h:866
ULONG NTAPI KeQueryTimeIncrement(VOID)
Definition: clock.c:153
#define DO_VERIFY_VOLUME
Definition: env_spec_w32.h:393
#define STATUS_INVALID_DEVICE_REQUEST
Definition: udferr_usr.h:138
#define CDROM_TAG_GESN
Definition: cdrom.h:734
#define InterlockedCompareExchange
Definition: interlocked.h:104
NTSTATUS RequestSend(_In_ PCDROM_DEVICE_EXTENSION DeviceExtension, _In_ WDFREQUEST Request, _In_ WDFIOTARGET IoTarget, _In_ ULONG Flags, _Out_opt_ PBOOLEAN RequestSent)
Definition: common.c:3793
UCHAR CdbLength
Definition: srb.h:250
#define FDO_HACK_GESN_IS_BAD
Definition: cdromp.h:134
GLuint buffer
Definition: glext.h:5915
_In_ WDFREQUEST Request
Definition: wdfdevice.h:547
#define MAXIMUM_IMMEDIATE_MCN_RETRIES
Definition: autorun.c:43
ULONG McnDisableCount
Definition: cdromp.h:367
#define NOTIFICATION_MEDIA_EVENT_MEDIA_CHANGE
Definition: scsi.h:97
UCHAR QueueAction
Definition: srb.h:249
struct _MEDIA_CHANGE_DETECTION_INFO::@995 Gesn
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
LONG NTAPI KeReleaseMutex(IN PKMUTEX Mutex, IN BOOLEAN Wait)
Definition: mutex.c:189
#define NOTIFICATION_DEVICE_BUSY_CLASS_MASK
Definition: scsi.h:39
ULONG TimeOutValue
Definition: srb.h:254
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _In_ ULONG _Out_opt_ PULONG _Out_opt_ PULONG ValueType
Definition: wdfregistry.h:279
#define _In_reads_opt_(size)
Definition: ms_sal.h:320
UCHAR SrbStatus
Definition: srb.h:243
#define SRB_STATUS(Status)
Definition: srb.h:381
#define SRB_CLASS_FLAGS_LOW_PRIORITY
Definition: cdrom.h:162
#define MCN_REG_AUTORUN_DISABLE_INSTANCE_NAME
Definition: autorun.c:45
#define SENSE_BUFFER_SIZE
Definition: cdrw_hw.h:1183
#define MCN_REG_SUBKEY_NAME
Definition: autorun.c:44
#define WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(_attributes, _contexttype)
Definition: wdfobject.h:170
#define IoSetCompletionRoutine(_Irp, _CompletionRoutine, _Context, _InvokeOnSuccess, _InvokeOnError, _InvokeOnCancel)
Definition: irp.cpp:498
FORCEINLINE LONGLONG WDF_REL_TIMEOUT_IN_MS(_In_ ULONGLONG Time)
Definition: wdfcore.h:80
struct _CDROM_DEVICE_EXTENSION * PCDROM_DEVICE_EXTENSION
Definition: cdrom.h:216
FORCEINLINE WDFDRIVER WdfGetDriver(VOID)
Definition: wdfdriver.h:194
#define STATUS_INVALID_DEVICE_STATE
Definition: udferr_usr.h:178
#define SP_UNTAGGED
Definition: srb.h:225
#define STATUS_IO_DEVICE_ERROR
Definition: udferr_usr.h:179
WDF_EXECUTION_LEVEL ExecutionLevel
Definition: wdfobject.h:120
#define SRB_STATUS_ERROR
Definition: srb.h:336
#define STATUS_INTERNAL_ERROR
Definition: ntstatus.h:465
#define STATUS_TIMEOUT
Definition: ntstatus.h:81
#define STATUS_DEVICE_PROTOCOL_ERROR
Definition: ntstatus.h:623
VOID RequestSetupMcnSyncIrp(_In_ PCDROM_DEVICE_EXTENSION DeviceExtension)
Definition: autorun.c:2749
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2055
#define STATUS_MEDIA_CHANGED
Definition: ntstatus.h:207
#define LOADING_MECHANISM_TRAY
Definition: scsi.h:972
#define NOTIFICATION_MEDIA_STATUS_CLASS_EVENTS
Definition: scsi.h:46
VOID DeviceSendNotification(_In_ PCDROM_DEVICE_EXTENSION DeviceExtension, _In_ const GUID *Guid, _In_ ULONG ExtraDataSize, _In_opt_ PVOID ExtraData)
Definition: common.c:799
PRTL_QUERY_REGISTRY_ROUTINE QueryRoutine
Definition: nt_native.h:109
* 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 CLASSP_REG_SUBKEY_NAME
Definition: cdromp.h:120
#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 DeviceInternalSetMediaChangeState(_In_ PCDROM_DEVICE_EXTENSION DeviceExtension, _In_ MEDIA_CHANGE_DETECTION_STATE NewState, _Inout_opt_ PMEDIA_CHANGE_DETECTION_STATE OldState)
Definition: autorun.c:630
Definition: Header.h:8
#define FREE_POOL(_PoolPtr)
Definition: cdrom.h:782
long LONG
Definition: pedump.c:60
Definition: devices.h:37
#define REG_MULTI_SZ
Definition: nt_native.h:1501
#define NOTIFICATION_OPERATIONAL_CHANGE_CLASS_MASK
Definition: scsi.h:34
UCHAR ScsiStatus
Definition: srb.h:244
GLenum GLuint GLenum GLsizei length
Definition: glext.h:5579
struct _SENSE_DATA SENSE_DATA
FORCEINLINE VOID WDF_TIMER_CONFIG_INIT(_Out_ PWDF_TIMER_CONFIG Config, _In_ PFN_WDF_TIMER EvtTimerFunc)
Definition: wdftimer.h:111
_In_ PFILE_OBJECT_CONTEXT FileObjectContext
Definition: cdrom.h:1212
FORCEINLINE VOID WDF_REQUEST_REUSE_PARAMS_INIT(_Out_ PWDF_REQUEST_REUSE_PARAMS Params, _In_ ULONG Flags, _In_ NTSTATUS Status)
Definition: wdfrequest.h:364
unsigned char BOOLEAN
int zero
Definition: sehframes.cpp:29
_In_ PCWSTR _Inout_ _At_ QueryTable EntryContext
Definition: rtlfuncs.h:4155
VOID RequestClearSendTime(_In_ WDFREQUEST Request)
Definition: common.c:111
struct _NOTIFICATION_MEDIA_STATUS * PNOTIFICATION_MEDIA_STATUS
union _CDB * PCDB
#define _In_
Definition: ms_sal.h:308
#define CDROM_HACK_MSFT_VIRTUAL_ODD
Definition: cdrom.h:101
#define SL_OVERRIDE_VERIFY_VOLUME
Definition: iotypes.h:1823
#define _In_z_
Definition: ms_sal.h:313
#define CLEAR_FLAG(Flags, Bit)
Definition: cdrom.h:1494
_In_ ULONG _In_opt_ WDFREQUEST _In_opt_ PVOID _In_ size_t _In_ PVOID _In_ size_t _Out_ size_t * DataLength
Definition: cdrom.h:1437
const char * LPCSTR
Definition: xmlstorage.h:183
void * PVOID
Definition: retypes.h:9
UCHAR QueueTag
Definition: srb.h:248
enum _MEDIA_CHANGE_DETECTION_STATE MEDIA_CHANGE_DETECTION_STATE
#define NOTIFICATION_MEDIA_EVENT_EJECT_REQUEST
Definition: scsi.h:94
#define GESN_DEVICE_BUSY_LOWER_THRESHOLD_100_MS
Definition: autorun.c:41
#define NOTIFICATION_MEDIA_EVENT_MEDIA_REMOVAL
Definition: scsi.h:96
#define TEST_FLAG(Flags, Bit)
Definition: cdrom.h:1495
ULONG TolerableDelay
Definition: wdftimer.h:95
#define PCHAR
Definition: match.c:90
BOOLEAN AutomaticSerialization
Definition: wdfworkitem.h:79
USHORT MaximumLength
Definition: env_spec_w32.h:377
int64_t LONGLONG
Definition: typedefs.h:68
#define NOTIFICATION_OPERATIONAL_EVENT_CHANGE_REQUESTED
Definition: scsi.h:51
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define SRB_STATUS_NOT_POWERED
Definition: srb.h:358
GLintptr offset
Definition: glext.h:5920
UCHAR Function
Definition: srb.h:242
_In_ WDFFILEOBJECT _In_ BOOLEAN IgnorePreviousMediaChanges
Definition: cdrom.h:1225
_In_ GUID _In_ PVOID ValueData
Definition: hubbusif.h:311
#define SRB_FLAGS_DISABLE_SYNCH_TRANSFER
Definition: srb.h:389
FORCEINLINE ULONG CountOfSetBitsUChar(UCHAR _X)
Definition: cdrom.h:1500
#define NOTIFICATION_OPERATIONAL_OPCODE_FEATURE_CHANGE
Definition: scsi.h:59
#define SRB_FLAGS_NO_KEEP_AWAKE
Definition: srb.h:404
ULONG dataLength
Definition: scsi.h:3751
PDEVICE_OBJECT DeviceObject
Definition: iotypes.h:3223
NTSYSAPI VOID NTAPI RtlFreeUnicodeString(PUNICODE_STRING UnicodeString)
#define RTL_SIZEOF_THROUGH_FIELD(type, field)
Definition: ntbasedef.h:672
USHORT Length
Definition: srb.h:241
enum _MEDIA_CHANGE_DETECTION_STATE * PMEDIA_CHANGE_DETECTION_STATE
#define IRP_MJ_INTERNAL_DEVICE_CONTROL
VOID NTAPI DeviceDisableGesn(_In_ WDFWORKITEM WorkItem)
Definition: autorun.c:1019
struct _SCSI_REQUEST_BLOCK SCSI_REQUEST_BLOCK
struct _NOTIFICATION_EXTERNAL_STATUS * PNOTIFICATION_EXTERNAL_STATUS
VOID NTAPI IoFreeMdl(PMDL Mdl)
Definition: iomdl.c:146
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING ValueName
Definition: wdfregistry.h:240
unsigned char UCHAR
Definition: xmlstorage.h:181
#define SRB_FLAGS_NO_DATA_TRANSFER
Definition: srb.h:394
char * PBOOLEAN
Definition: retypes.h:11
VOID NTAPI KeInitializeMutex(IN PKMUTEX Mutex, IN ULONG Level)
Definition: mutex.c:67
BOOLEAN PreventMediaRemoval
Definition: ntddstor.h:343
#define NOTIFICATION_OPERATIONAL_OPCODE_FEATURE_ADDED
Definition: scsi.h:60
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
static const WCHAR L[]
Definition: oid.c:1250
FORCEINLINE VOID FREE_PORT_ALLOCATED_SENSE_BUFFER(_In_ PCDROM_DEVICE_EXTENSION DeviceExtension, _In_ PSCSI_REQUEST_BLOCK Srb)
Definition: cdrom.h:839
#define InterlockedDecrement
Definition: armddk.h:52
_IRQL_requires_max_(_IRQL_requires_max_() BOOLEANDeviceIsMediaChangeDisabledForClass(_In_ PCDROM_DEVICE_EXTENSION DeviceExtension) PASSIVE_LEVEL)
Definition: autorun.c:66
#define NOTIFICATION_DEVICE_BUSY_CLASS_EVENTS
Definition: scsi.h:48
#define VOID
Definition: acefi.h:82
#define RTL_REGISTRY_HANDLE
Definition: nt_native.h:168
#define _Inout_opt_
Definition: ms_sal.h:379
VOID NTAPI DeviceMainTimerTickHandler(_In_ WDFTIMER Timer)
Definition: autorun.c:2820
FORCEINLINE BOOLEAN PORT_ALLOCATED_SENSE(_In_ PCDROM_DEVICE_EXTENSION DeviceExtension, _In_ PSCSI_REQUEST_BLOCK Srb)
Definition: cdrom.h:826
MEDIA_CHANGE_DETECTION_STATE LastReportedMediaDetectionState
Definition: cdromp.h:203
struct _cl_event * event
Definition: glext.h:7739
#define PASSIVE_LEVEL
Definition: env_spec_w32.h:693
__drv_aliasesMem FORCEINLINE PIO_STACK_LOCATION IoGetNextIrpStackLocation(_In_ PIRP Irp)
Definition: iofuncs.h:2695
#define IOCTL_SCSI_EXECUTE_IN
Definition: cdrw_hw.h:1451
#define TRACE_LEVEL_ERROR
Definition: storswtr.h:27
#define TRACE_LEVEL_WARNING
Definition: storswtr.h:28
PMDL NTAPI IoAllocateMdl(IN PVOID VirtualAddress, IN ULONG Length, IN BOOLEAN SecondaryBuffer, IN BOOLEAN ChargeQuota, IN PIRP Irp)
Definition: iomdl.c:22
#define IOCTL_SCSI_EXECUTE_NONE
Definition: cdrw_hw.h:1453
#define NOTIFICATION_BUSY_EVENT_LO_CHANGE
Definition: scsi.h:116
FORCEINLINE VOID WDF_OBJECT_ATTRIBUTES_INIT(_Out_ PWDF_OBJECT_ATTRIBUTES Attributes)
Definition: wdfobject.h:147
__drv_aliasesMem FORCEINLINE PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(_In_ PIRP Irp)
Definition: iofuncs.h:2793
UCHAR SenseInfoBufferLength
Definition: srb.h:251
#define CLASSP_REG_MMC_DETECTION_VALUE_NAME
Definition: cdromp.h:123
#define GESN_TIMEOUT_VALUE
Definition: autorun.c:39
#define GESN_BUFFER_SIZE
Definition: autorun.c:40
#define NOTIFICATION_EXTERNAL_REQUEST_CLASS_EVENTS
Definition: scsi.h:45
#define InterlockedIncrement
Definition: armddk.h:53
#define CDROM_TAG_MEDIA_CHANGE_DETECTION
Definition: cdrom.h:725
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
VOID DeviceReleaseQueue(_In_ WDFDEVICE Device)
Definition: common.c:1179
unsigned short USHORT
Definition: pedump.c:61
#define KEY_ALL_ACCESS
Definition: nt_native.h:1041
NTSYSAPI NTSTATUS NTAPI RtlAnsiStringToUnicodeString(PUNICODE_STRING DestinationString, PANSI_STRING SourceString, BOOLEAN AllocateDestinationString)
struct _CDB::_CDB6GENERIC CDB6GENERIC
struct _NOTIFICATION_EVENT_STATUS_HEADER * PNOTIFICATION_EVENT_STATUS_HEADER
IO_COMPLETION_ROUTINE RequestMcnSyncIrpCompletion
Definition: autorun.c:2691
WDFOBJECT ParentObject
Definition: wdfobject.h:130
#define SRB_SIMPLE_TAG_REQUEST
Definition: srb.h:415
POWER_SETTING_CALLBACK DevicePowerSettingCallback
Definition: cdrom.h:1395
#define NOTIFICATION_BUSY_STATUS_NO_EVENT
Definition: scsi.h:118
unsigned int * PULONG
Definition: retypes.h:1
#define WdfObjectGetTypedContext(handle, type)
Definition: wdfobject.h:404
#define NULL
Definition: types.h:112
FORCEINLINE BOOLEAN IsVolumeMounted(_In_ PDEVICE_OBJECT DeviceObject)
Definition: cdrom.h:1514
_In_ BOOLEAN AllowDriveToSleep
Definition: classpnp.h:1275
#define IOCTL_MCN_SYNC_FAKE_IOCTL
Definition: cdrom.h:181
#define STATUS_IO_TIMEOUT
Definition: udferr_usr.h:163
#define WDF_NO_OBJECT_ATTRIBUTES
Definition: wdftypes.h:105
VOID DeviceSetMediaChangeStateEx(_In_ PCDROM_DEVICE_EXTENSION DeviceExtension, _In_ MEDIA_CHANGE_DETECTION_STATE NewState, _Inout_opt_ PMEDIA_CHANGE_DETECTION_STATE OldState)
Definition: autorun.c:751
#define _In_reads_bytes_opt_(size)
Definition: ms_sal.h:322
MEDIA_CHANGE_DETECTION_STATE LastKnownMediaDetectionState
Definition: cdromp.h:199
PVOID SenseInfoBuffer
Definition: srb.h:256
struct tagContext Context
Definition: acpixf.h:1034
VOID NTAPI IoFreeIrp(IN PIRP Irp)
Definition: irp.c:1666
#define NOTIFICATION_OPERATIONAL_CHANGE_CLASS_EVENTS
Definition: scsi.h:43
WDFREQUEST MediaChangeRequest
Definition: cdromp.h:246
#define SRB_FUNCTION_EXECUTE_SCSI
Definition: srb.h:307
unsigned int ULONG
Definition: retypes.h:1
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
UCHAR AdditionalSenseLength
Definition: cdrw_hw.h:1173
#define SRB_STATUS_SUCCESS
Definition: srb.h:333
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define MCN_REG_AUTORUN_ENABLE_INSTANCE_NAME
Definition: autorun.c:46
PIRP NTAPI IoAllocateIrp(IN CCHAR StackSize, IN BOOLEAN ChargeQuota)
Definition: irp.c:615
PMEDIA_CHANGE_DETECTION_INFO MediaChangeDetectionInfo
Definition: cdrom.h:563
#define STATUS_SUCCESS
Definition: shellext.h:65
struct _NOTIFICATION_BUSY_STATUS * PNOTIFICATION_BUSY_STATUS
enum _CDROM_DETECTION_STATE CDROM_DETECTION_STATE
LARGE_INTEGER SystemTime
Definition: ioevent.h:92
_Must_inspect_result_ _In_ PWDF_WORKITEM_CONFIG _In_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFWORKITEM * WorkItem
Definition: wdfworkitem.h:110
UCHAR AdditionalSenseCode
Definition: cdrw_hw.h:1175
struct _NAMED_PIPE_CREATE_PARAMETERS * Parameters
Definition: iotypes.h:3128
#define CDROM_TAG_AUTORUN_DISABLE
Definition: cdrom.h:724
struct _CDB::_GET_EVENT_STATUS_NOTIFICATION GET_EVENT_STATUS_NOTIFICATION
#define RTL_QUERY_REGISTRY_REQUIRED
Definition: nt_native.h:132
signed int * PLONG
Definition: retypes.h:5
static SERVICE_STATUS status
Definition: service.c:31
#define CDROM_TEST_UNIT_READY_TIMEOUT
Definition: cdrom.h:128
#define APC_LEVEL
Definition: env_spec_w32.h:695
FORCEINLINE VOID IoSetNextIrpStackLocation(_Inout_ PIRP Irp)
Definition: iofuncs.h:2680
#define SET_FLAG(Flags, Bit)
Definition: cdrom.h:1493
FxIrp * irp
#define SCSI_SENSE_UNIT_ATTENTION
Definition: cdrw_hw.h:1193
#define RtlCompareMemory(s1, s2, l)
Definition: env_spec_w32.h:465
LONGLONG QuadPart
Definition: typedefs.h:114
#define IRP_MJ_DEVICE_CONTROL
Definition: rdpdr.c:52
NTKRNLVISTAAPI NTSTATUS NTAPI PoRegisterPowerSettingCallback(_In_opt_ PDEVICE_OBJECT DeviceObject, _In_ LPCGUID SettingGuid, _In_ PPOWER_SETTING_CALLBACK Callback, _In_opt_ PVOID Context, _Outptr_opt_ PVOID *Handle)
Definition: po.c:14
#define SCSI_ADSENSE_MEDIUM_CHANGED
Definition: cdrw_hw.h:1288
#define PAGED_CODE()
#define NT_ASSERT
Definition: rtlfuncs.h:3310
#define REG_SZ
Definition: layer.c:22
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _In_ ULONG ValueLength
Definition: wdfregistry.h:271
Definition: ps.c:97