ReactOS  0.4.13-dev-73-gcfe54aa
autorun.c
Go to the documentation of this file.
1 /*++
2 
3 Copyright (C) Microsoft Corporation, 1991 - 1999
4 
5 Module Name:
6 
7  autorun.c
8 
9 Abstract:
10 
11  Code for support of media change detection in the class driver
12 
13 Environment:
14 
15  kernel mode only
16 
17 Notes:
18 
19 
20 Revision History:
21 
22 --*/
23 
24 #include "classp.h"
25 
26 #include <wmidata.h>
27 
28 #define GESN_TIMEOUT_VALUE (0x4)
29 #define GESN_BUFFER_SIZE (0x8)
30 #define MAXIMUM_IMMEDIATE_MCN_RETRIES (0x20)
31 #define MCN_REG_SUBKEY_NAME (L"MediaChangeNotification")
32 #define MCN_REG_AUTORUN_DISABLE_INSTANCE_NAME (L"AlwaysDisableMCN")
33 #define MCN_REG_AUTORUN_ENABLE_INSTANCE_NAME (L"AlwaysEnableMCN")
34 
36 
37 //
38 // Only send polling irp when device is fully powered up and a
39 // power down irp is not in progress.
40 //
41 // NOTE: This helps close a window in time where a polling irp could cause
42 // a drive to spin up right after it has powered down. The problem is
43 // that SCSIPORT, ATAPI and SBP2 will be in the process of powering
44 // down (which may take a few seconds), but won't know that. It would
45 // then get a polling irp which will be put into its queue since it
46 // the disk isn't powered down yet. Once the disk is powered down it
47 // will find the polling irp in the queue and then power up the
48 // device to do the poll. They do not want to check if the polling
49 // irp has the SRB_NO_KEEP_AWAKE flag here since it is in a critical
50 // path and would slow down all I/Os. A better way to fix this
51 // would be to serialize the polling and power down irps so that
52 // only one of them is sent to the device at a time.
53 //
54 #define ClasspCanSendPollingIrp(fdoExtension) \
55  ((fdoExtension->DevicePowerState == PowerDeviceD0) && \
56  (! fdoExtension->PowerDownInProgress) )
57 
58 BOOLEAN
59 NTAPI
63  );
64 
66 NTAPI
70  );
71 
72 BOOLEAN
73 NTAPI
77  );
78 
79 VOID
80 NTAPI
84  IN BOOLEAN Wait,
85  IN BOOLEAN KnownStateChange // can ignore oldstate == unknown
86  );
87 
89 NTAPI
97  );
98 
99 VOID
100 NTAPI
104  IN ULONG CountDown
105  );
106 
107 IO_WORKITEM_ROUTINE ClasspFailurePredict;
108 
109 NTSTATUS
110 NTAPI
114  );
115 
116 
117 #if ALLOC_PRAGMA
118 
119 #pragma alloc_text(PAGE, ClassInitializeMediaChangeDetection)
120 #pragma alloc_text(PAGE, ClassEnableMediaChangeDetection)
121 #pragma alloc_text(PAGE, ClassDisableMediaChangeDetection)
122 #pragma alloc_text(PAGE, ClassCleanupMediaChangeDetection)
123 #pragma alloc_text(PAGE, ClasspMediaChangeRegistryCallBack)
124 #pragma alloc_text(PAGE, ClasspInitializePolling)
125 
126 #pragma alloc_text(PAGE, ClasspIsMediaChangeDisabledDueToHardwareLimitation)
127 #pragma alloc_text(PAGE, ClasspMediaChangeDeviceInstanceOverride)
128 #pragma alloc_text(PAGE, ClasspIsMediaChangeDisabledForClass)
129 
130 #pragma alloc_text(PAGE, ClassSetFailurePredictionPoll)
131 #pragma alloc_text(PAGE, ClasspDisableTimer)
132 #pragma alloc_text(PAGE, ClasspEnableTimer)
133 
134 #endif
135 
136 // ISSUE -- make this public?
137 VOID
138 NTAPI
141  )
142 {
143  //
144  // For post-NT5.1 work, need to move EjectSynchronizationEvent
145  // to be a MUTEX so we can attempt to grab it here and benefit
146  // from deadlock detection. This will allow checking if the media
147  // has been locked by programs before broadcasting these events.
148  // (what's the point of broadcasting if the media is not locked?)
149  //
150  // This would currently only be a slight optimization. For post-NT5.1,
151  // it would allow us to send a single PERSISTENT_PREVENT to MMC devices,
152  // thereby cleaning up a lot of the ejection code. Then, when the
153  // ejection request occured, we could see if any locks for the media
154  // existed. if locked, broadcast. if not, we send the eject irp.
155  //
156 
157  //
158  // for now, just always broadcast. make this a public routine,
159  // so class drivers can add special hacks to broadcast this for their
160  // non-MMC-compliant devices also from sense codes.
161  //
162 
163  DBGTRACE(ClassDebugTrace, ("ClassSendEjectionNotification: media EJECT_REQUEST"));
165  &GUID_IO_MEDIA_EJECT_REQUEST,
166  0,
167  NULL);
168  return;
169 }
170 
171 VOID
172 NTAPI
175  IN const GUID * Guid,
177  IN PVOID ExtraData
178  )
179 {
181  ULONG requiredSize;
182 
183  requiredSize =
184  (sizeof(TARGET_DEVICE_CUSTOM_NOTIFICATION) - sizeof(UCHAR)) +
186 
187  if (requiredSize > 0x0000ffff) {
188  // MAX_USHORT, max total size for these events!
190  "Error sending event: size too large! (%x)\n",
191  requiredSize));
192  return;
193  }
194 
196  requiredSize,
197  'oNcS');
198 
199  //
200  // if none allocated, exit
201  //
202 
203  if (notification == NULL) {
204  return;
205  }
206 
207  //
208  // Prepare and send the request!
209  //
210 
211  RtlZeroMemory(notification, requiredSize);
212  notification->Version = 1;
213  notification->Size = (USHORT)(requiredSize);
214  notification->FileObject = NULL;
215  notification->NameBufferOffset = -1;
216  notification->Event = *Guid;
217  RtlCopyMemory(notification->CustomDataBuffer, ExtraData, ExtraDataSize);
218 
220  notification,
221  NULL, NULL);
222 
224  notification = NULL;
225  return;
226 }
227 
228 /*++////////////////////////////////////////////////////////////////////////////
229 
230 ClasspInterpretGesnData()
231 
232 Routine Description:
233 
234  This routine will interpret the data returned for a GESN command, and
235  (if appropriate) set the media change event, and broadcast the
236  appropriate events to user mode for applications who care.
237 
238 Arguments:
239 
240  FdoExtension - the device
241 
242  DataBuffer - the resulting data from a GESN event.
243  requires at least EIGHT valid bytes (header == 4, data == 4)
244 
245  ResendImmediately - whether or not to immediately resend the request.
246  this should be FALSE if there was no event, FALSE if the reported
247  event was of the DEVICE BUSY class, else true.
248 
249 Return Value:
250 
251  None
252 
253 Notes:
254 
255  DataBuffer must be at least four bytes of valid data (header == 4 bytes),
256  and have at least eight bytes of allocated memory (all events == 4 bytes).
257 
258  The call to StartNextPacket may occur before this routine is completed.
259  the operational change notifications are informational in nature, and
260  while useful, are not necessary to ensure proper operation. For example,
261  if the device morphs to no longer supporting WRITE commands, all further
262  write commands will fail. There exists a small timing window wherein
263  IOCTL_IS_DISK_WRITABLE may be called and get an incorrect response. If
264  a device supports software write protect, it is expected that the
265  application can handle such a case.
266 
267  NOTE: perhaps setting the updaterequired byte to one should be done here.
268  if so, it relies upon the setting of a 32-byte value to be an atomic
269  operation. unfortunately, there is no simple way to notify a class driver
270  which wants to know that the device behavior requires updating.
271 
272  Not ready events may be sent every second. For example, if we were
273  to minimize the number of asynchronous notifications, an application may
274  register just after a large busy time was reported. This would then
275  prevent the application from knowing the device was busy until some
276  arbitrarily chosen timeout has occurred. Also, the GESN request would
277  have to still occur, since it checks for non-busy events (such as user
278  keybutton presses and media change events) as well. The specification
279  states that the lower-numered events get reported first, so busy events,
280  while repeating, will only be reported when all other events have been
281  cleared from the device.
282 
283 --*/
284 VOID
285 NTAPI
289  IN PBOOLEAN ResendImmediately
290  )
291 {
293  LONG dataLength;
294  LONG requiredLength;
295 
296  info = FdoExtension->MediaChangeDetectionInfo;
297 
298  //
299  // note: don't allocate anything in this routine so that we can
300  // always just 'return'.
301  //
302 
303  *ResendImmediately = FALSE;
304 
305  if (Header->NEA) {
306  return;
307  }
308  if (Header->NotificationClass == NOTIFICATION_NO_CLASS_EVENTS) {
309  return;
310  }
311 
312  //
313  // HACKHACK - REF #0001
314  // This loop is only taken initially, due to the inability to reliably
315  // auto-detect drives that report events correctly at boot. When we
316  // detect this behavior during the normal course of running, we will
317  // disable the hack, allowing more efficient use of the system. This
318  // should occur "nearly" instantly, as the drive should have multiple
319  // events queue'd (ie. power, morphing, media).
320  //
321 
322  if (info->Gesn.HackEventMask) {
323 
324  //
325  // all events use the low four bytes of zero to indicate
326  // that there was no change in status.
327  //
328 
329  UCHAR thisEvent = Header->ClassEventData[0] & 0xf;
330  UCHAR lowestSetBit;
331  UCHAR thisEventBit = (1 << Header->NotificationClass);
332 
333  ASSERT(TEST_FLAG(info->Gesn.EventMask, thisEventBit));
334 
335 
336  //
337  // some bit magic here... this results in the lowest set bit only
338  //
339 
340  lowestSetBit = info->Gesn.EventMask;
341  lowestSetBit &= (info->Gesn.EventMask - 1);
342  lowestSetBit ^= (info->Gesn.EventMask);
343 
344  if (thisEventBit != lowestSetBit) {
345 
346  //
347  // HACKHACK - REF #0001
348  // the first time we ever see an event set that is not the lowest
349  // set bit in the request (iow, highest priority), we know that the
350  // hack is no longer required, as the device is ignoring "no change"
351  // events when a real event is waiting in the other requested queues.
352  //
353 
355  "Classpnp => GESN::NONE: Compliant drive found, "
356  "removing GESN hack (%x, %x)\n",
357  thisEventBit, info->Gesn.EventMask));
358 
359  info->Gesn.HackEventMask = FALSE;
360 
361  } else if (thisEvent == 0) {
362 
363  //
364  // HACKHACK - REF #0001
365  // note: this hack prevents poorly implemented firmware from constantly
366  // returning "No Event". we do this by cycling through the
367  // supported list of events here.
368  //
369 
370  SET_FLAG(info->Gesn.NoChangeEventMask, thisEventBit);
371  CLEAR_FLAG(info->Gesn.EventMask, thisEventBit);
372 
373  //
374  // if we have cycled through all supported event types, then
375  // we need to reset the events we are asking about. else we
376  // want to resend this request immediately in case there was
377  // another event pending.
378  //
379 
380  if (info->Gesn.EventMask == 0) {
381  info->Gesn.EventMask = info->Gesn.NoChangeEventMask;
382  info->Gesn.NoChangeEventMask = 0;
383  } else {
384  *ResendImmediately = TRUE;
385  }
386  return;
387  }
388 
389  } // end if (info->Gesn.HackEventMask)
390 
391  dataLength =
392  (Header->EventDataLength[0] << 8) |
393  (Header->EventDataLength[1] & 0xff);
394  dataLength -= 2;
395  requiredLength = 4; // all events are four bytes
396 
397  if (dataLength < requiredLength) {
399  "Classpnp => GESN returned only %x bytes data for fdo %p\n",
400  dataLength, FdoExtension->DeviceObject));
401  return;
402  }
403  if (dataLength != requiredLength) {
405  "Classpnp => GESN returned too many (%x) bytes data for fdo %p\n",
406  dataLength, FdoExtension->DeviceObject));
407  dataLength = 4;
408  }
409 
410 /*
411  ClasspSendNotification(FdoExtension,
412  &GUID_IO_GENERIC_GESN_EVENT,
413  sizeof(NOTIFICATION_EVENT_STATUS_HEADER) + dataLength,
414  Header)
415 */
416 
417  switch (Header->NotificationClass) {
418 
420 
421  PNOTIFICATION_EXTERNAL_STATUS externalInfo =
422  (PNOTIFICATION_EXTERNAL_STATUS)(Header->ClassEventData);
423  DEVICE_EVENT_EXTERNAL_REQUEST externalData;
424 
425  //
426  // unfortunately, due to time constraints, we will only notify
427  // about keys being pressed, and not released. this makes keys
428  // single-function, but simplifies the code significantly.
429  //
430 
431  if (externalInfo->ExternalEvent !=
433  break;
434  }
435 
436  *ResendImmediately = TRUE;
438  "Classpnp => GESN::EXTERNAL: Event: %x Status %x Req %x\n",
439  externalInfo->ExternalEvent, externalInfo->ExternalStatus,
440  (externalInfo->Request[0] << 8) | externalInfo->Request[1]
441  ));
442 
443  RtlZeroMemory(&externalData, sizeof(DEVICE_EVENT_EXTERNAL_REQUEST));
444  externalData.Version = 1;
445  externalData.DeviceClass = 0;
446  externalData.ButtonStatus = externalInfo->ExternalEvent;
447  externalData.Request =
448  (externalInfo->Request[0] << 8) |
449  (externalInfo->Request[1] & 0xff);
450  KeQuerySystemTime(&(externalData.SystemTime));
452 
453  DBGTRACE(ClassDebugTrace, ("ClasspInterpretGesnData: media DEVICE_EXTERNAL_REQUEST"));
455  &GUID_IO_DEVICE_EXTERNAL_REQUEST,
457  &externalData);
458  return;
459  }
460 
462 
463  PNOTIFICATION_MEDIA_STATUS mediaInfo =
464  (PNOTIFICATION_MEDIA_STATUS)(Header->ClassEventData);
465 
467  break;
468  }
469 
470  *ResendImmediately = TRUE;
472  "Classpnp => GESN::MEDIA: Event: %x Status %x\n",
473  mediaInfo->MediaEvent, mediaInfo->MediaStatus));
474 
475  if ((mediaInfo->MediaEvent == NOTIFICATION_MEDIA_EVENT_NEW_MEDIA) ||
477 
478 
479  if (TEST_FLAG(FdoExtension->DeviceObject->Characteristics,
481  (ClassGetVpb(FdoExtension->DeviceObject) != NULL) &&
482  (ClassGetVpb(FdoExtension->DeviceObject)->Flags & VPB_MOUNTED)
483  ) {
484 
485  SET_FLAG(FdoExtension->DeviceObject->Flags, DO_VERIFY_VOLUME);
486 
487  }
488  InterlockedIncrement((PLONG)&FdoExtension->MediaChangeCount);
490  MediaPresent,
491  FALSE,
492  TRUE);
493 
494  } else if (mediaInfo->MediaEvent == NOTIFICATION_MEDIA_EVENT_MEDIA_REMOVAL) {
495 
498  FALSE,
499  TRUE);
500 
501  } else if (mediaInfo->MediaEvent == NOTIFICATION_MEDIA_EVENT_EJECT_REQUEST) {
502 
504  "Classpnp => GESN Ejection request received!\n"));
506 
507  }
508  break;
509 
510  }
511 
512  case NOTIFICATION_DEVICE_BUSY_CLASS_EVENTS: { // lowest priority events...
513 
514  PNOTIFICATION_BUSY_STATUS busyInfo =
515  (PNOTIFICATION_BUSY_STATUS)(Header->ClassEventData);
517 
518  //
519  // NOTE: we never actually need to immediately retry for these
520  // events: if one exists, the device is busy, and if not,
521  // we still don't want to retry.
522  //
523 
525  break;
526  }
527 
528  //
529  // else we want to report the approximated time till it's ready.
530  //
531 
532  RtlZeroMemory(&busyData, sizeof(DEVICE_EVENT_BECOMING_READY));
533  busyData.Version = 1;
534  busyData.Reason = busyInfo->DeviceBusyStatus;
535  busyData.Estimated100msToReady = (busyInfo->Time[0] << 8) |
536  (busyInfo->Time[1] & 0xff);
537 
539  "Classpnp => GESN::BUSY: Event: %x Status %x Time %x\n",
540  busyInfo->DeviceBusyEvent, busyInfo->DeviceBusyStatus,
541  busyData.Estimated100msToReady
542  ));
543 
544  DBGTRACE(ClassDebugTrace, ("ClasspInterpretGesnData: media BECOMING_READY"));
546  &GUID_IO_DEVICE_BECOMING_READY,
548  &busyData);
549  break;
550  }
551 
552  default: {
553 
554  break;
555 
556  }
557 
558  } // end switch on notification class
559  return;
560 }
561 
562 /*++////////////////////////////////////////////////////////////////////////////
563 
564 ClasspInternalSetMediaChangeState()
565 
566 Routine Description:
567 
568  This routine will (if appropriate) set the media change event for the
569  device. The event will be set if the media state is changed and
570  media change events are enabled. Otherwise the media state will be
571  tracked but the event will not be set.
572 
573  This routine will lock out the other media change routines if possible
574  but if not a media change notification may be lost after the enable has
575  been completed.
576 
577 Arguments:
578 
579  FdoExtension - the device
580 
581  MediaPresent - indicates whether the device has media inserted into it
582  (TRUE) or not (FALSE).
583 
584 Return Value:
585 
586  none
587 
588 --*/
589 VOID
590 NTAPI
594  IN BOOLEAN KnownStateChange // can ignore oldstate == unknown
595  )
596 {
597 #if DBG
598  PCSTR states[] = {"Unknown", "Present", "Not Present"};
599 #endif
600  MEDIA_CHANGE_DETECTION_STATE oldMediaState;
601  PMEDIA_CHANGE_DETECTION_INFO info = FdoExtension->MediaChangeDetectionInfo;
602  ULONG data;
603  //NTSTATUS status;
604 
605  ASSERT((NewState >= MediaUnknown) && (NewState <= MediaNotPresent));
606 
607  if(info == NULL) {
608  return;
609  }
610 
611  oldMediaState = InterlockedExchange(
612  (PLONG)(&info->MediaChangeDetectionState),
613  (LONG)NewState);
614 
615  if((oldMediaState == MediaUnknown) && (!KnownStateChange)) {
616 
617  //
618  // The media was in an indeterminate state before - don't notify for
619  // this change.
620  //
621 
623  "ClassSetMediaChangeState: State was unknown - this may "
624  "not be a change\n"));
625  return;
626 
627  } else if(oldMediaState == NewState) {
628 
629  //
630  // Media is in the same state it was before.
631  //
632 
633  return;
634  }
635 
636  if(info->MediaChangeDetectionDisableCount != 0) {
637 
639  ("ClassSetMediaChangeState: MCN not enabled, state "
640  "changed from %s to %s\n",
641  states[oldMediaState], states[NewState]));
642  return;
643 
644  }
645 
647  ("ClassSetMediaChangeState: State change from %s to %s\n",
648  states[oldMediaState], states[NewState]));
649 
650  //
651  // make the data useful -- it used to always be zero.
652  //
653  data = FdoExtension->MediaChangeCount;
654 
655  if (NewState == MediaPresent) {
656 
657  DBGTRACE(ClassDebugTrace, ("ClasspInternalSetMediaChangeState: media ARRIVAL"));
659  &GUID_IO_MEDIA_ARRIVAL,
660  sizeof(ULONG),
661  &data);
662 
663  }
664  else if (NewState == MediaNotPresent) {
665 
666  DBGTRACE(ClassDebugTrace, ("ClasspInternalSetMediaChangeState: media REMOVAL"));
668  &GUID_IO_MEDIA_REMOVAL,
669  sizeof(ULONG),
670  &data);
671 
672  } else {
673 
674  //
675  // Don't notify of changed going to unknown.
676  //
677 
678  return;
679  }
680 
681  return;
682 } // end ClasspInternalSetMediaChangeState()
683 
684 /*++////////////////////////////////////////////////////////////////////////////
685 
686 ClassSetMediaChangeState()
687 
688 Routine Description:
689 
690  This routine will (if appropriate) set the media change event for the
691  device. The event will be set if the media state is changed and
692  media change events are enabled. Otherwise the media state will be
693  tracked but the event will not be set.
694 
695  This routine will lock out the other media change routines if possible
696  but if not a media change notification may be lost after the enable has
697  been completed.
698 
699 Arguments:
700 
701  FdoExtension - the device
702 
703  MediaPresent - indicates whether the device has media inserted into it
704  (TRUE) or not (FALSE).
705 
706  Wait - indicates whether the function should wait until it can acquire
707  the synchronization lock or not.
708 
709 Return Value:
710 
711  none
712 
713 --*/
714 VOID
715 NTAPI
719  IN BOOLEAN Wait,
720  IN BOOLEAN KnownStateChange // can ignore oldstate == unknown
721  )
722 {
723  PMEDIA_CHANGE_DETECTION_INFO info = FdoExtension->MediaChangeDetectionInfo;
726 
727  DBGTRACE(ClassDebugMCN, ("> ClasspSetMediaChangeStateEx"));
728 
729  //
730  // Reset SMART status on media removal as the old status may not be
731  // valid when there is no media in the device or when new media is
732  // inserted.
733  //
734 
735  if (NewState == MediaNotPresent) {
736 
737  FdoExtension->FailurePredicted = FALSE;
738  FdoExtension->FailureReason = 0;
739 
740  }
741 
742 
743  zero.QuadPart = 0;
744 
745  if(info == NULL) {
746  return;
747  }
748 
749  status = KeWaitForMutexObject(&info->MediaChangeMutex,
750  Executive,
751  KernelMode,
752  FALSE,
753  ((Wait != FALSE) ? NULL : &zero));
754 
755  if(status == STATUS_TIMEOUT) {
756 
757  //
758  // Someone else is in the process of setting the media state
759  //
760 
761  DBGWARN(("ClasspSetMediaChangeStateEx - timed out waiting for mutex"));
762  return;
763  }
764 
765  //
766  // Change the media present state and signal an event, if applicable
767  //
768 
769  ClasspInternalSetMediaChangeState(FdoExtension, NewState, KnownStateChange);
770 
771  KeReleaseMutex(&info->MediaChangeMutex, FALSE);
772 
773  DBGTRACE(ClassDebugMCN, ("< ClasspSetMediaChangeStateEx"));
774 
775  return;
776 } // end ClassSetMediaChangeStateEx()
777 
778 VOID
779 NTAPI
783  IN BOOLEAN Wait
784  )
785 {
787  return;
788 }
789 
790 /*++////////////////////////////////////////////////////////////////////////////
791 
792 ClasspMediaChangeDetectionCompletion()
793 
794 Routine Description:
795 
796  This routine handles the completion of the test unit ready irps used to
797  determine if the media has changed. If the media has changed, this code
798  signals the named event to wake up other system services that react to
799  media change (aka AutoPlay).
800 
801 Arguments:
802 
803  DeviceObject - the object for the completion
804  Irp - the IRP being completed
805  Context - the SRB from the IRP
806 
807 Return Value:
808 
809  NTSTATUS
810 
811 --*/
812 NTSTATUS
813 NTAPI
816  PIRP Irp,
817  PVOID Context
818  )
819 {
821  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
822  PCLASS_PRIVATE_FDO_DATA fdoData;
824  //PIO_STACK_LOCATION nextIrpStack;
826  BOOLEAN retryImmediately = FALSE;
827 
828  //
829  // Since the class driver created this request, it's completion routine
830  // will not get a valid device object handed in. Use the one in the
831  // irp stack instead
832  //
833 
835  fdoExtension = DeviceObject->DeviceExtension;
836  fdoData = fdoExtension->PrivateFdoData;
837  info = fdoExtension->MediaChangeDetectionInfo;
838 
839  ASSERT(info->MediaChangeIrp != NULL);
841  DBGTRACE(ClassDebugMCN, ("> ClasspMediaChangeDetectionCompletion: Device %p completed MCN irp %p.", DeviceObject, Irp));
842 
843  /*
844  * HACK for IoMega 2GB Jaz drive:
845  * This drive spins down on its own to preserve the media.
846  * When spun down, TUR fails with 2/4/0 (SCSI_SENSE_NOT_READY/SCSI_ADSENSE_LUN_NOT_READY/?).
847  * ClassInterpretSenseInfo would then call ClassSendStartUnit to spin the media up, which defeats the
848  * purpose of the spindown.
849  * So in this case, make this into a successful TUR.
850  * This allows the drive to stay spun down until it is actually accessed again.
851  * (If the media were actually removed, TUR would fail with 2/3a/0 ).
852  * This hack only applies to drives with the CAUSE_NOT_REPORTABLE_HACK bit set; this
853  * is set by disk.sys when HackCauseNotReportableHack is set for the drive in its BadControllers list.
854  */
855  if ((SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) &&
857  (srb->SenseInfoBufferLength >= RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseCode))){
858 
859  PSENSE_DATA senseData = srb->SenseInfoBuffer;
860 
861  if ((senseData->SenseKey == SCSI_SENSE_NOT_READY) &&
864  }
865  }
866 
867 
868  //
869  // use ClassInterpretSenseInfo() to check for media state, and also
870  // to call ClassError() with correct parameters.
871  //
873  if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
874 
875  DBGTRACE(ClassDebugMCN, ("ClasspMediaChangeDetectionCompletion - failed - srb status=%s, sense=%s/%s/%s.", DBGGETSRBSTATUSSTR(srb), DBGGETSENSECODESTR(srb), DBGGETADSENSECODESTR(srb), DBGGETADSENSEQUALIFIERSTR(srb)));
876 
878  srb,
879  IRP_MJ_SCSI,
880  0,
881  0,
882  &status,
883  NULL);
884 
885  }
886  else {
887 
889 
890  if (!info->Gesn.Supported) {
891 
892  DBGTRACE(ClassDebugMCN, ("ClasspMediaChangeDetectionCompletion - succeeded and GESN NOT supported, setting MediaPresent."));
893 
894  //
895  // success != media for GESN case
896  //
897 
899 
900  }
901  else {
902  DBGTRACE(ClassDebugMCN, ("ClasspMediaChangeDetectionCompletion - succeeded (GESN supported)."));
903  }
904  }
905 
906  if (info->Gesn.Supported) {
907 
908  if (status == STATUS_DATA_OVERRUN) {
909  DBGTRACE(ClassDebugMCN, ("ClasspMediaChangeDetectionCompletion - Overrun"));
911  }
912 
913  if (!NT_SUCCESS(status)) {
914  DBGTRACE(ClassDebugMCN, ("ClasspMediaChangeDetectionCompletion: GESN failed with status %x", status));
915  } else {
916 
917  //
918  // for GESN, need to interpret the results of the data.
919  // this may also require an immediate retry
920  //
921 
922  if (Irp->IoStatus.Information == 8 ) {
923  ClasspInterpretGesnData(fdoExtension,
924  (PVOID)info->Gesn.Buffer,
925  &retryImmediately);
926  }
927 
928  } // end of NT_SUCCESS(status)
929 
930  } // end of Info->Gesn.Supported
931 
932  //
933  // free port-allocated sense buffer, if any.
934  //
935 
936  if (PORT_ALLOCATED_SENSE(fdoExtension, srb)) {
937  FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, srb);
938  }
939 
940  //
941  // Remember the IRP and SRB for use the next time.
942  //
943 
945  IoGetNextIrpStackLocation(Irp)->Parameters.Scsi.Srb = srb;
946 
947  //
948  // Reset the MCN timer.
949  //
950 
951  ClassResetMediaChangeTimer(fdoExtension);
952 
953  //
954  // run a sanity check to make sure we're not recursing continuously
955  //
956 
957  if (retryImmediately) {
958 
959  info->MediaChangeRetryCount++;
960  if (info->MediaChangeRetryCount > MAXIMUM_IMMEDIATE_MCN_RETRIES) {
961  ASSERT(!"Recursing too often in MCN?");
962  info->MediaChangeRetryCount = 0;
963  retryImmediately = FALSE;
964  }
965 
966  } else {
967 
968  info->MediaChangeRetryCount = 0;
969 
970  }
971 
972 
973  //
974  // release the remove lock....
975  //
976 
977  {
978  UCHAR uniqueValue;
979  ClassAcquireRemoveLock(DeviceObject, (PIRP)(&uniqueValue));
981 
982 
983  //
984  // set the irp as not in use
985  //
986  {
987  volatile LONG irpWasInUse;
988  irpWasInUse = InterlockedCompareExchange(&info->MediaChangeIrpInUse, 0, 1);
989  #if _MSC_FULL_VER != 13009111 // This compiler always takes the wrong path here.
990  ASSERT(irpWasInUse);
991  #endif
992  }
993 
994  //
995  // now send it again before we release our last remove lock
996  //
997 
998  if (retryImmediately) {
999  ClasspSendMediaStateIrp(fdoExtension, info, 0);
1000  }
1001  else {
1002  DBGTRACE(ClassDebugMCN, ("ClasspMediaChangeDetectionCompletion - not retrying immediately"));
1003  }
1004 
1005  //
1006  // release the temporary remove lock
1007  //
1008 
1009  ClassReleaseRemoveLock(DeviceObject, (PIRP)(&uniqueValue));
1010  }
1011 
1012  DBGTRACE(ClassDebugMCN, ("< ClasspMediaChangeDetectionCompletion"));
1013 
1015 }
1016 
1017 /*++////////////////////////////////////////////////////////////////////////////
1018 
1019 ClasspSendTestUnitIrp() - ISSUE-2000/02/20-henrygab - not documented
1020 
1021 Routine Description:
1022 
1023  This routine
1024 
1025 Arguments:
1026 
1027  DeviceObject -
1028  Irp -
1029 
1030 Return Value:
1031 
1032 
1033 --*/
1034 PIRP
1035 NTAPI
1039  IN BOOLEAN UseGesn
1040 )
1041 {
1042  PSCSI_REQUEST_BLOCK srb;
1043  PIO_STACK_LOCATION irpStack;
1044  PIO_STACK_LOCATION nextIrpStack;
1045  NTSTATUS status;
1046  PCDB cdb;
1047  PIRP irp;
1048  PVOID buffer;
1049 
1050  //
1051  // Setup the IRP to perform a test unit ready.
1052  //
1053 
1054  irp = Info->MediaChangeIrp;
1055 
1056  ASSERT(irp);
1057 
1058  if (irp == NULL) {
1059  return NULL;
1060  }
1061 
1062  //
1063  // don't keep sending this if the device is being removed.
1064  //
1065 
1066  status = ClassAcquireRemoveLock(FdoExtension->DeviceObject, irp);
1067  if (status == REMOVE_COMPLETE) {
1069  return NULL;
1070  }
1071  else if (status == REMOVE_PENDING) {
1072  ClassReleaseRemoveLock(FdoExtension->DeviceObject, irp);
1073  return NULL;
1074  }
1075  else {
1076  ASSERT(status == NO_REMOVE);
1077  }
1078 
1079  irp->IoStatus.Status = STATUS_SUCCESS;
1080  irp->IoStatus.Information = 0;
1081  irp->Flags = 0;
1082  irp->UserBuffer = NULL;
1083 
1084  //
1085  // If the irp is sent down when the volume needs to be
1086  // verified, CdRomUpdateGeometryCompletion won't complete
1087  // it since it's not associated with a thread. Marking
1088  // it to override the verify causes it always be sent
1089  // to the port driver
1090  //
1091 
1092  irpStack = IoGetCurrentIrpStackLocation(irp);
1093  irpStack->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
1094 
1095  nextIrpStack = IoGetNextIrpStackLocation(irp);
1097  nextIrpStack->Parameters.Scsi.Srb = &(Info->MediaChangeSrb);
1098 
1099  //
1100  // Prepare the SRB for execution.
1101  //
1102 
1103  srb = nextIrpStack->Parameters.Scsi.Srb;
1104  buffer = srb->SenseInfoBuffer;
1105  RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
1107 
1108 
1109  srb->QueueTag = SP_UNTAGGED;
1111  srb->Length = sizeof(SCSI_REQUEST_BLOCK);
1113  srb->SenseInfoBuffer = buffer;
1114  srb->SrbStatus = 0;
1115  srb->ScsiStatus = 0;
1116  srb->OriginalRequest = irp;
1118 
1119  srb->SrbFlags = FdoExtension->SrbFlags;
1120  SET_FLAG(srb->SrbFlags, Info->SrbFlags);
1121 
1122  srb->TimeOutValue = FdoExtension->TimeOutValue * 2;
1123 
1124  if (srb->TimeOutValue == 0) {
1125 
1126  if (FdoExtension->TimeOutValue == 0) {
1127 
1129  "ClassSendTestUnitIrp: FdoExtension->TimeOutValue "
1130  "is set to zero?! -- resetting to 10\n"));
1131  srb->TimeOutValue = 10 * 2; // reasonable default
1132 
1133  } else {
1134 
1136  "ClassSendTestUnitIrp: Someone set "
1137  "srb->TimeOutValue to zero?! -- resetting to %x\n",
1138  FdoExtension->TimeOutValue * 2));
1139  srb->TimeOutValue = FdoExtension->TimeOutValue * 2;
1140 
1141  }
1142 
1143  }
1144 
1145  if (!UseGesn) {
1146 
1147  srb->CdbLength = 6;
1148  srb->DataTransferLength = 0;
1150  nextIrpStack->Parameters.DeviceIoControl.IoControlCode =
1152  srb->DataBuffer = NULL;
1153  srb->DataTransferLength = 0;
1154  irp->MdlAddress = NULL;
1155 
1156  cdb = (PCDB) &srb->Cdb[0];
1157  cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
1158 
1159  } else {
1160 
1161  ASSERT(Info->Gesn.Buffer);
1162 
1163  srb->TimeOutValue = GESN_TIMEOUT_VALUE; // much shorter timeout for GESN
1164 
1165  srb->CdbLength = 10;
1167  nextIrpStack->Parameters.DeviceIoControl.IoControlCode =
1169  srb->DataBuffer = Info->Gesn.Buffer;
1170  srb->DataTransferLength = Info->Gesn.BufferSize;
1171  irp->MdlAddress = Info->Gesn.Mdl;
1172 
1173  cdb = (PCDB) &srb->Cdb[0];
1174  cdb->GET_EVENT_STATUS_NOTIFICATION.OperationCode =
1176  cdb->GET_EVENT_STATUS_NOTIFICATION.Immediate = 1;
1177  cdb->GET_EVENT_STATUS_NOTIFICATION.EventListLength[0] =
1178  (UCHAR)((Info->Gesn.BufferSize) >> 8);
1179  cdb->GET_EVENT_STATUS_NOTIFICATION.EventListLength[1] =
1180  (UCHAR)((Info->Gesn.BufferSize) & 0xff);
1181  cdb->GET_EVENT_STATUS_NOTIFICATION.NotificationClassRequest =
1182  Info->Gesn.EventMask;
1183 
1184  }
1185 
1188  srb,
1189  TRUE,
1190  TRUE,
1191  TRUE);
1192 
1193  return irp;
1194 
1195 }
1196 
1197 /*++////////////////////////////////////////////////////////////////////////////
1198 
1199 ClasspSendMediaStateIrp() - ISSUE-2000/02/20-henrygab - not documented
1200 
1201 Routine Description:
1202 
1203  This routine
1204 
1205 Arguments:
1206 
1207  DeviceObject -
1208  Irp -
1209 
1210 Return Value:
1211 
1212 --*/
1213 VOID
1214 NTAPI
1218  IN ULONG CountDown
1219  )
1220 {
1221  BOOLEAN requestPending = FALSE;
1222  LONG irpInUse;
1223  //LARGE_INTEGER zero;
1224  //NTSTATUS status;
1225 
1226  DBGTRACE(ClassDebugMCN, ("> ClasspSendMediaStateIrp"));
1227 
1228  if (((FdoExtension->CommonExtension.CurrentState != IRP_MN_START_DEVICE) ||
1229  (FdoExtension->DevicePowerState != PowerDeviceD0)
1230  ) &&
1231  (!Info->MediaChangeIrpLost)) {
1232 
1233  //
1234  // the device may be stopped, powered down, or otherwise queueing io,
1235  // so should not timeout the autorun irp (yet) -- set to zero ticks.
1236  // scattered code relies upon this to not prematurely "lose" an
1237  // autoplay irp that was queued.
1238  //
1239 
1240  Info->MediaChangeIrpTimeInUse = 0;
1241  }
1242 
1243  //
1244  // if the irp is not in use, mark it as such.
1245  //
1246 
1247  irpInUse = InterlockedCompareExchange(&Info->MediaChangeIrpInUse, 1, 0);
1248 
1249  if (irpInUse) {
1250 
1251  LONG timeInUse;
1252 
1253  timeInUse = InterlockedIncrement(&Info->MediaChangeIrpTimeInUse);
1254 
1255  DebugPrint((ClassDebugMCN, "ClasspSendMediaStateIrp: irp in use for "
1256  "%x seconds when synchronizing for MCD\n", timeInUse));
1257 
1258  if (Info->MediaChangeIrpLost == FALSE) {
1259 
1260  if (timeInUse > MEDIA_CHANGE_TIMEOUT_TIME) {
1261 
1262  //
1263  // currently set to five minutes. hard to imagine a drive
1264  // taking that long to spin up.
1265  //
1266 
1268  "CdRom%d: Media Change Notification has lost "
1269  "it's irp and doesn't know where to find it. "
1270  "Leave it alone and it'll come home dragging "
1271  "it's stack behind it.\n",
1272  FdoExtension->DeviceNumber));
1273  Info->MediaChangeIrpLost = TRUE;
1274  }
1275  }
1276 
1277  DBGTRACE(ClassDebugMCN, ("< ClasspSendMediaStateIrp - irpInUse"));
1278  return;
1279 
1280  }
1281 
1282  TRY {
1283 
1284  if (Info->MediaChangeDetectionDisableCount != 0) {
1285  DebugPrint((ClassDebugTrace, "ClassCheckMediaState: device %p has "
1286  " detection disabled \n", FdoExtension->DeviceObject));
1287  LEAVE;
1288  }
1289 
1290  if (FdoExtension->DevicePowerState != PowerDeviceD0) {
1291 
1292  if (TEST_FLAG(Info->SrbFlags, SRB_FLAGS_NO_KEEP_AWAKE)) {
1294  "ClassCheckMediaState: device %p is powered "
1295  "down and flags are set to let it sleep\n",
1296  FdoExtension->DeviceObject));
1298  LEAVE;
1299  }
1300 
1301  //
1302  // NOTE: we don't increment the time in use until our power state
1303  // changes above. this way, we won't "lose" the autoplay irp.
1304  // it's up to the lower driver to determine if powering up is a
1305  // good idea.
1306  //
1307 
1309  "ClassCheckMediaState: device %p needs to powerup "
1310  "to handle this io (may take a few extra seconds).\n",
1311  FdoExtension->DeviceObject));
1312 
1313  }
1314 
1315  Info->MediaChangeIrpTimeInUse = 0;
1316  Info->MediaChangeIrpLost = FALSE;
1317 
1318  if (CountDown == 0) {
1319 
1320  PIRP irp;
1321 
1323  "ClassCheckMediaState: timer expired\n"));
1324 
1325  if (Info->MediaChangeDetectionDisableCount != 0) {
1327  "ClassCheckMediaState: detection disabled\n"));
1328  LEAVE;
1329  }
1330 
1331  //
1332  // Prepare the IRP for the test unit ready
1333  //
1334 
1336  Info,
1337  Info->Gesn.Supported);
1338 
1339  //
1340  // Issue the request.
1341  //
1342 
1344  "ClasspSendMediaStateIrp: Device %p getting TUR "
1345  " irp %p\n", FdoExtension->DeviceObject, irp));
1346 
1347  if (irp == NULL) {
1348  LEAVE;
1349  }
1350 
1351 
1352  //
1353  // note: if we send it to the class dispatch routines, there is
1354  // a timing window here (since they grab the remove lock)
1355  // where we'd be removed. ELIMINATE the window by grabbing
1356  // the lock ourselves above and sending it to the lower
1357  // device object directly or to the device's StartIo
1358  // routine (which doesn't acquire the lock).
1359  //
1360 
1361  requestPending = TRUE;
1362 
1363  DBGTRACE(ClassDebugMCN, (" ClasspSendMediaStateIrp - calling IoCallDriver."));
1364  IoCallDriver(FdoExtension->CommonExtension.LowerDeviceObject, irp);
1365  }
1366 
1367  } FINALLY {
1368 
1369  if(requestPending == FALSE) {
1370  irpInUse = InterlockedCompareExchange(&Info->MediaChangeIrpInUse, 0, 1);
1371  #if _MSC_FULL_VER != 13009111 // This compiler always takes the wrong path here.
1372  ASSERT(irpInUse);
1373  #endif
1374  }
1375 
1376  }
1377 
1378  DBGTRACE(ClassDebugMCN, ("< ClasspSendMediaStateIrp"));
1379 
1380  return;
1381 } // end ClasspSendMediaStateIrp()
1382 
1383 /*++////////////////////////////////////////////////////////////////////////////
1384 
1385 ClassCheckMediaState()
1386 
1387 Routine Description:
1388 
1389  This routine is called by the class driver to test for a media change
1390  condition and/or poll for disk failure prediction. It should be called
1391  from the class driver's IO timer routine once per second.
1392 
1393 Arguments:
1394 
1395  FdoExtension - the device extension
1396 
1397 Return Value:
1398 
1399  none
1400 
1401 --*/
1402 VOID
1403 NTAPI
1406  )
1407 {
1408  PMEDIA_CHANGE_DETECTION_INFO info = FdoExtension->MediaChangeDetectionInfo;
1409  LONG countDown;
1410 
1411  if(info == NULL) {
1413  "ClassCheckMediaState: detection not enabled\n"));
1414  return;
1415  }
1416 
1417  //
1418  // Media change support is active and the IRP is waiting. Decrement the
1419  // timer. There is no MP protection on the timer counter. This code
1420  // is the only code that will manipulate the timer counter and only one
1421  // instance of it should be running at any given time.
1422  //
1423 
1424  countDown = InterlockedDecrement(&(info->MediaChangeCountDown));
1425 
1426  //
1427  // Try to acquire the media change event. If we can't do it immediately
1428  // then bail out and assume the caller will try again later.
1429  //
1431  info,
1432  countDown);
1433 
1434  return;
1435 } // end ClassCheckMediaState()
1436 
1437 /*++////////////////////////////////////////////////////////////////////////////
1438 
1439 ClassResetMediaChangeTimer()
1440 
1441 Routine Description:
1442 
1443  Resets the media change count down timer to the default number of seconds.
1444 
1445 Arguments:
1446 
1447  FdoExtension - the device to reset the timer for
1448 
1449 Return Value:
1450 
1451  None
1452 
1453 --*/
1454 VOID
1455 NTAPI
1458  )
1459 {
1460  PMEDIA_CHANGE_DETECTION_INFO info = FdoExtension->MediaChangeDetectionInfo;
1461 
1462  if(info != NULL) {
1463  InterlockedExchange(&(info->MediaChangeCountDown),
1465  }
1466  return;
1467 } // end ClassResetMediaChangeTimer()
1468 
1469 /*++////////////////////////////////////////////////////////////////////////////
1470 
1471 ClasspInitializePolling() - ISSUE-2000/02/20-henrygab - not documented
1472 
1473 Routine Description:
1474 
1475  This routine
1476 
1477 Arguments:
1478 
1479  DeviceObject -
1480  Irp -
1481 
1482 Return Value:
1483 
1484 --*/
1485 NTSTATUS
1486 NTAPI
1490  )
1491 {
1492  PDEVICE_OBJECT fdo = FdoExtension->DeviceObject;
1493  //PCLASS_PRIVATE_FDO_DATA fdoData = FdoExtension->PrivateFdoData;
1494 
1495  //ULONG size;
1497  PIRP irp;
1498 
1499  PAGED_CODE();
1500 
1501  if (FdoExtension->MediaChangeDetectionInfo != NULL) {
1502  return STATUS_SUCCESS;
1503  }
1504 
1508 
1509  if(info != NULL) {
1511 
1512  FdoExtension->KernelModeMcnContext.FileObject = (PVOID)-1;
1513  FdoExtension->KernelModeMcnContext.DeviceObject = (PVOID)-1;
1514  FdoExtension->KernelModeMcnContext.LockCount = 0;
1515  FdoExtension->KernelModeMcnContext.McnDisableCount = 0;
1516 
1517  /*
1518  * Allocate an IRP to carry the Test-Unit-Ready.
1519  * Allocate an extra IRP stack location
1520  * so we can cache our device object in the top location.
1521  */
1522  irp = IoAllocateIrp((CCHAR)(fdo->StackSize+1), FALSE);
1523 
1524  if (irp != NULL) {
1525 
1526  PVOID buffer;
1527 
1532 
1533  if (buffer != NULL) {
1534  PIO_STACK_LOCATION irpStack;
1535  PSCSI_REQUEST_BLOCK srb;
1536  //PCDB cdb;
1537 
1538  srb = &(info->MediaChangeSrb);
1539  info->MediaChangeIrp = irp;
1540  info->SenseBuffer = buffer;
1541 
1542  /*
1543  * For the driver that creates an IRP, there is no 'current' stack location.
1544  * Step down one IRP stack location so that the extra top one
1545  * becomes our 'current' one.
1546  */
1548 
1549  /*
1550  * Cache our device object in the extra top IRP stack location
1551  * so we have it in our completion routine.
1552  */
1553  irpStack = IoGetCurrentIrpStackLocation(irp);
1554  irpStack->DeviceObject = fdo;
1555 
1556  /*
1557  * Now start setting up the next IRP stack location for the call like any driver would.
1558  */
1559  irpStack = IoGetNextIrpStackLocation(irp);
1560  irpStack->Parameters.Scsi.Srb = srb;
1561  info->MediaChangeIrp = irp;
1562 
1563  //
1564  // Initialize the SRB
1565  //
1566 
1567  RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
1568 
1569  //
1570  // Initialize and set up the sense information buffer
1571  //
1572 
1574  srb->SenseInfoBuffer = buffer;
1576 
1577  //
1578  // Set default values for the media change notification
1579  // configuration.
1580  //
1581 
1582  info->MediaChangeCountDown = MEDIA_CHANGE_DEFAULT_TIME;
1583  info->MediaChangeDetectionDisableCount = 0;
1584 
1585  //
1586  // Assume that there is initially no media in the device
1587  // only notify upper layers if there is something there
1588  //
1589 
1590  info->MediaChangeDetectionState = MediaUnknown;
1591 
1592  info->MediaChangeIrpTimeInUse = 0;
1593  info->MediaChangeIrpLost = FALSE;
1594 
1595  //
1596  // setup all extra flags we'll be setting for this irp
1597  //
1598  info->SrbFlags = 0;
1599  if (AllowDriveToSleep) {
1601  }
1605 
1606  KeInitializeMutex(&info->MediaChangeMutex, 0x100);
1607 
1608  //
1609  // It is ok to support media change events on this
1610  // device.
1611  //
1612 
1613  FdoExtension->MediaChangeDetectionInfo = info;
1614 
1615  //
1616  // NOTE: the DeviceType is FILE_DEVICE_CD_ROM even
1617  // when the device supports DVD (no need to
1618  // check for FILE_DEVICE_DVD, as it's not a
1619  // valid check).
1620  //
1621 
1622  if (FdoExtension->DeviceObject->DeviceType == FILE_DEVICE_CD_ROM){
1623 
1624  NTSTATUS status;
1625 
1627  "ClasspInitializePolling: Testing for GESN\n"));
1629  if (NT_SUCCESS(status)) {
1631  "ClasspInitializePolling: GESN available "
1632  "for %p\n", FdoExtension->DeviceObject));
1633  ASSERT(info->Gesn.Supported );
1634  ASSERT(info->Gesn.Buffer != NULL);
1635  ASSERT(info->Gesn.BufferSize != 0);
1636  ASSERT(info->Gesn.EventMask != 0);
1637  // must return here, for ASSERTs to be valid.
1638  return STATUS_SUCCESS;
1639  }
1641  "ClasspInitializePolling: GESN *NOT* available "
1642  "for %p\n", FdoExtension->DeviceObject));
1643  }
1644 
1645  ASSERT(info->Gesn.Supported == 0);
1646  ASSERT(info->Gesn.Buffer == NULL);
1647  ASSERT(info->Gesn.BufferSize == 0);
1648  ASSERT(info->Gesn.EventMask == 0);
1649  info->Gesn.Supported = 0; // just in case....
1650  return STATUS_SUCCESS;
1651  }
1652 
1653  IoFreeIrp(irp);
1654  }
1655 
1656  ExFreePool(info);
1657  }
1658 
1659  //
1660  // nothing to free here
1661  //
1663 
1664 } // end ClasspInitializePolling()
1665 
1666 NTSTATUS
1667 NTAPI
1671  )
1672 {
1675  PSTORAGE_ADAPTER_DESCRIPTOR adapterDescriptor;
1677  PIRP irp;
1678  KEVENT event;
1679  BOOLEAN retryImmediately;
1680  ULONG i;
1681  ULONG atapiResets;
1682 
1683 
1684  PAGED_CODE();
1685  ASSERT(Info == FdoExtension->MediaChangeDetectionInfo);
1686 
1687  //
1688  // read if we already know the abilities of the device
1689  //
1690 
1694  (PULONG)&detectionState);
1695 
1696  if (detectionState == ClassDetectionUnsupported) {
1697  goto ExitWithError;
1698  }
1699 
1700  //
1701  // check if the device has a hack flag saying never to try this.
1702  //
1703 
1704  if (TEST_FLAG(FdoExtension->PrivateFdoData->HackFlags,
1706 
1707  detectionState = ClassDetectionUnsupported;
1712  goto ExitWithError;
1713 
1714  }
1715 
1716 
1717  //
1718  // else go through the process since we allocate buffers and
1719  // get all sorts of device settings.
1720  //
1721 
1722  if (Info->Gesn.Buffer == NULL) {
1725  '??cS');
1726  }
1727  if (Info->Gesn.Buffer == NULL) {
1729  goto ExitWithError;
1730  }
1731  if (Info->Gesn.Mdl != NULL) {
1732  IoFreeMdl(Info->Gesn.Mdl);
1733  }
1734  Info->Gesn.Mdl = IoAllocateMdl(Info->Gesn.Buffer,
1736  FALSE, FALSE, NULL);
1737  if (Info->Gesn.Mdl == NULL) {
1739  goto ExitWithError;
1740  }
1741 
1742  MmBuildMdlForNonPagedPool(Info->Gesn.Mdl);
1743  Info->Gesn.BufferSize = GESN_BUFFER_SIZE;
1744  Info->Gesn.EventMask = 0;
1745 
1746  //
1747  // all items are prepared to use GESN (except the event mask, so don't
1748  // optimize this part out!).
1749  //
1750  // now see if it really works. we have to loop through this because
1751  // many SAMSUNG (and one COMPAQ) drives timeout when requesting
1752  // NOT_READY events, even when the IMMEDIATE bit is set. :(
1753  //
1754  // using a drive list is cumbersome, so this might fix the problem.
1755  //
1756 
1757  adapterDescriptor = FdoExtension->AdapterDescriptor;
1758  atapiResets = 0;
1759  retryImmediately = TRUE;
1760  for (i = 0; (i < 16) && (retryImmediately != FALSE); i++) {
1761 
1763  if (irp == NULL) {
1765  goto ExitWithError;
1766  }
1767 
1768  ASSERT(TEST_FLAG(Info->MediaChangeSrb.SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE));
1769 
1770  //
1771  // replace the completion routine with a different one this time...
1772  //
1773 
1776  &event,
1777  TRUE, TRUE, TRUE);
1779 
1780  status = IoCallDriver(FdoExtension->CommonExtension.LowerDeviceObject, irp);
1781 
1782  if (status == STATUS_PENDING) {
1784  Executive,
1785  KernelMode,
1786  FALSE,
1787  NULL);
1789  }
1790  ClassReleaseRemoveLock(FdoExtension->DeviceObject, irp);
1791 
1792  if (SRB_STATUS(Info->MediaChangeSrb.SrbStatus) != SRB_STATUS_SUCCESS) {
1793  ClassInterpretSenseInfo(FdoExtension->DeviceObject,
1794  &(Info->MediaChangeSrb),
1795  IRP_MJ_SCSI,
1796  0,
1797  0,
1798  &status,
1799  NULL);
1800  }
1801 
1802  if ((adapterDescriptor->BusType == BusTypeAtapi) &&
1803  (Info->MediaChangeSrb.SrbStatus == SRB_STATUS_BUS_RESET)
1804  ) {
1805 
1806  //
1807  // ATAPI unfortunately returns SRB_STATUS_BUS_RESET instead
1808  // of SRB_STATUS_TIMEOUT, so we cannot differentiate between
1809  // the two. if we get this status four time consecutively,
1810  // stop trying this command. it is too late to change ATAPI
1811  // at this point, so special-case this here. (07/10/2001)
1812  // NOTE: any value more than 4 may cause the device to be
1813  // marked missing.
1814  //
1815 
1816  atapiResets++;
1817  if (atapiResets >= 4) {
1819  goto ExitWithError;
1820  }
1821  }
1822 
1823  if (status == STATUS_DATA_OVERRUN) {
1825  }
1826 
1828  (status == STATUS_TIMEOUT) ||
1831  ) {
1832 
1833  //
1834  // with these error codes, we don't ever want to try this command
1835  // again on this device, since it reacts poorly.
1836  //
1837 
1843  "Classpnp => GESN test failed %x for fdo %p\n",
1844  status, FdoExtension->DeviceObject));
1845  goto ExitWithError;
1846 
1847 
1848  }
1849 
1850  if (!NT_SUCCESS(status)) {
1851 
1852  //
1853  // this may be other errors that should not disable GESN
1854  // for all future start_device calls.
1855  //
1856 
1858  "Classpnp => GESN test failed %x for fdo %p\n",
1859  status, FdoExtension->DeviceObject));
1860  goto ExitWithError;
1861  }
1862 
1863  if (i == 0) {
1864 
1865  //
1866  // the first time, the request was just retrieving a mask of
1867  // available bits. use this to mask future requests.
1868  //
1869 
1870  header = (PNOTIFICATION_EVENT_STATUS_HEADER)(Info->Gesn.Buffer);
1871 
1873  "Classpnp => Fdo %p supports event mask %x\n",
1874  FdoExtension->DeviceObject, header->SupportedEventClasses));
1875 
1876 
1877  if (TEST_FLAG(header->SupportedEventClasses,
1880  "Classpnp => GESN supports MCN\n"));
1881  }
1882  if (TEST_FLAG(header->SupportedEventClasses,
1885  "Classpnp => GESN supports DeviceBusy\n"));
1886  }
1887  Info->Gesn.EventMask = header->SupportedEventClasses;
1888 
1889  //
1890  // realistically, we are only considering the following events:
1891  // EXTERNAL REQUEST - this is being tested for play/stop/etc.
1892  // MEDIA STATUS - autorun and ejection requests.
1893  // DEVICE BUSY - to allow us to predict when media will be ready.
1894  // therefore, we should not bother querying for the other,
1895  // unknown events. clear all but the above flags.
1896  //
1897 
1898  Info->Gesn.EventMask &=
1902 
1903 
1904  //
1905  // HACKHACK - REF #0001
1906  // Some devices will *never* report an event if we've also requested
1907  // that it report lower-priority events. this is due to a
1908  // misunderstanding in the specification wherein a "No Change" is
1909  // interpreted to be a real event. what should occur is that the
1910  // device should ignore "No Change" events when multiple event types
1911  // are requested unless there are no other events waiting. this
1912  // greatly reduces the number of requests that the host must send
1913  // to determine if an event has occurred. Since we must work on all
1914  // drives, default to enabling the hack until we find evidence of
1915  // proper firmware.
1916  //
1917 
1918  if (CountOfSetBitsUChar(Info->Gesn.EventMask) == 1) {
1920  "Classpnp => GESN hack %s for FDO %p\n",
1921  "not required", FdoExtension->DeviceObject));
1922  } else {
1924  "Classpnp => GESN hack %s for FDO %p\n",
1925  "enabled", FdoExtension->DeviceObject));
1926  Info->Gesn.HackEventMask = 1;
1927  }
1928 
1929  } else {
1930 
1931  //
1932  // not the first time looping through, so interpret the results.
1933  //
1934 
1936  (PVOID)Info->Gesn.Buffer,
1937  &retryImmediately);
1938 
1939  }
1940 
1941  } // end loop of GESN requests....
1942 
1943  //
1944  // we can only use this if it can be relied upon for media changes,
1945  // since we are (by definition) no longer going to be polling via
1946  // a TEST_UNIT_READY irp, and drives will not report UNIT ATTENTION
1947  // for this command (although a filter driver, such as one for burning
1948  // cd's, might still fake those errors).
1949  //
1950  // since we also rely upon NOT_READY events to change the cursor
1951  // into a "wait" cursor, we can't use GESN without NOT_READY support.
1952  //
1953 
1954  if (TEST_FLAG(Info->Gesn.EventMask,
1956  TEST_FLAG(Info->Gesn.EventMask,
1958  ) {
1959 
1961  "Classpnp => Enabling GESN support for fdo %p\n",
1962  FdoExtension->DeviceObject));
1963  Info->Gesn.Supported = TRUE;
1964 
1969 
1970  return STATUS_SUCCESS;
1971 
1972  }
1973 
1975  "Classpnp => GESN available but not enabled for fdo %p\n",
1976  FdoExtension->DeviceObject));
1977  goto ExitWithError;
1978 
1979  // fall through...
1980 
1981 ExitWithError:
1982  if (Info->Gesn.Mdl) {
1983  IoFreeMdl(Info->Gesn.Mdl);
1984  Info->Gesn.Mdl = NULL;
1985  }
1986  if (Info->Gesn.Buffer) {
1987  ExFreePool(Info->Gesn.Buffer);
1988  Info->Gesn.Buffer = NULL;
1989  }
1990  Info->Gesn.Supported = 0;
1991  Info->Gesn.EventMask = 0;
1992  Info->Gesn.BufferSize = 0;
1993  return STATUS_NOT_SUPPORTED;
1994 
1995 }
1996 
1997 /*++////////////////////////////////////////////////////////////////////////////
1998 
1999 ClassInitializeTestUnitPolling()
2000 
2001 Routine Description:
2002 
2003  This routine will initialize MCN regardless of the settings stored
2004  in the registry. This should be used with caution, as some devices
2005  react badly to constant io. (i.e. never spin down, continuously cycling
2006  media in changers, ejection of media, etc.) It is highly suggested to
2007  use ClassInitializeMediaChangeDetection() instead.
2008 
2009 Arguments:
2010 
2011  FdoExtension is the device to poll
2012 
2013  AllowDriveToSleep says whether to attempt to allow the drive to sleep
2014  or not. This only affects system-known spin down states, so if a
2015  drive spins itself down, this has no effect until the system spins
2016  it down.
2017 
2018 Return Value:
2019 
2020 --*/
2021 NTSTATUS
2022 NTAPI
2026  )
2027 {
2029 } // end ClassInitializeTestUnitPolling()
2030 
2031 /*++////////////////////////////////////////////////////////////////////////////
2032 
2033 ClassInitializeMediaChangeDetection()
2034 
2035 Routine Description:
2036 
2037  This routine checks to see if it is safe to initialize MCN (the back end
2038  to autorun) for a given device. It will then check the device-type wide
2039  key "Autorun" in the service key (for legacy reasons), and then look in
2040  the device-specific key to potentially override that setting.
2041 
2042  If MCN is to be enabled, all necessary structures and memory are
2043  allocated and initialized.
2044 
2045  This routine MUST be called only from the ClassInit() callback.
2046 
2047 Arguments:
2048 
2049  FdoExtension - the device to initialize MCN for, if appropriate
2050 
2051  EventPrefix - unused, legacy argument. Set to zero.
2052 
2053 Return Value:
2054 
2055 --*/
2056 VOID
2057 NTAPI
2061  )
2062 {
2063  PDEVICE_OBJECT fdo = FdoExtension->DeviceObject;
2064  NTSTATUS status;
2065 
2067  fdo->DriverObject);
2068 
2069  BOOLEAN disabledForBadHardware;
2070  BOOLEAN disabled;
2071  BOOLEAN instanceOverride;
2072 
2073  PAGED_CODE();
2074 
2075  //
2076  // NOTE: This assumes that ClassInitializeMediaChangeDetection is always
2077  // called in the context of the ClassInitDevice callback. If called
2078  // after then this check will have already been made and the
2079  // once a second timer will not have been enabled.
2080  //
2081 
2082  disabledForBadHardware = ClasspIsMediaChangeDisabledDueToHardwareLimitation(
2083  FdoExtension,
2084  &(driverExtension->RegistryPath)
2085  );
2086 
2087  if (disabledForBadHardware) {
2089  "ClassInitializeMCN: Disabled due to hardware"
2090  "limitations for this device"));
2091  return;
2092  }
2093 
2094  //
2095  // autorun should now be enabled by default for all media types.
2096  //
2097 
2099  FdoExtension,
2100  &(driverExtension->RegistryPath)
2101  );
2102 
2104  "ClassInitializeMCN: Class MCN is %s\n",
2105  (disabled ? "disabled" : "enabled")));
2106 
2108  FdoExtension,
2109  &instanceOverride); // default value
2110 
2111  if (!NT_SUCCESS(status)) {
2113  "ClassInitializeMCN: Instance using default\n"));
2114  } else {
2116  "ClassInitializeMCN: Instance override: %s MCN\n",
2117  (instanceOverride ? "Enabling" : "Disabling")));
2118  disabled = !instanceOverride;
2119  }
2120 
2122  "ClassInitializeMCN: Instance MCN is %s\n",
2123  (disabled ? "disabled" : "enabled")));
2124 
2125  if (disabled) {
2126  return;
2127  }
2128 
2129  //
2130  // if the drive is not a CDROM, allow the drive to sleep
2131  //
2132  if (FdoExtension->DeviceObject->DeviceType == FILE_DEVICE_CD_ROM) {
2134  } else {
2136  }
2137 
2138  return;
2139 } // end ClassInitializeMediaChangeDetection()
2140 
2141 /*++////////////////////////////////////////////////////////////////////////////
2142 
2143 ClasspMediaChangeDeviceInstanceOverride()
2144 
2145 Routine Description:
2146 
2147  The user can override the global setting to enable or disable Autorun on a
2148  specific cdrom device via the control panel. This routine checks and/or
2149  sets this value.
2150 
2151 Arguments:
2152 
2153  FdoExtension - the device to set/get the value for
2154  Value - the value to use in a set
2155  SetValue - whether to set the value
2156 
2157 Return Value:
2158 
2159  TRUE - Autorun is disabled
2160  FALSE - Autorun is not disabled (Default)
2161 
2162 --*/
2163 NTSTATUS
2164 NTAPI
2168  )
2169 {
2170  HANDLE deviceParameterHandle; // cdrom instance key
2171  HANDLE driverParameterHandle; // cdrom specific key
2172  RTL_QUERY_REGISTRY_TABLE queryTable[3];
2173  OBJECT_ATTRIBUTES objectAttributes;
2174  UNICODE_STRING subkeyName;
2175  NTSTATUS status;
2176  ULONG alwaysEnable;
2177  ULONG alwaysDisable;
2178  ULONG i;
2179 
2180 
2181  PAGED_CODE();
2182 
2183  deviceParameterHandle = NULL;
2184  driverParameterHandle = NULL;
2186  alwaysEnable = FALSE;
2187  alwaysDisable = FALSE;
2188 
2189  TRY {
2190 
2194  &deviceParameterHandle
2195  );
2196  if (!NT_SUCCESS(status)) {
2197 
2198  //
2199  // this can occur when a new device is added to the system
2200  // this is due to cdrom.sys being an 'essential' driver
2201  //
2203  "ClassMediaChangeDeviceInstanceDisabled: "
2204  "Could not open device registry key [%lx]\n", status));
2205  LEAVE;
2206  }
2207 
2209  InitializeObjectAttributes(&objectAttributes,
2210  &subkeyName,
2212  deviceParameterHandle,
2214 
2215  status = ZwCreateKey(&driverParameterHandle,
2216  KEY_READ,
2217  &objectAttributes,
2218  0,
2221  NULL);
2222 
2223  if (!NT_SUCCESS(status)) {
2225  "ClassMediaChangeDeviceInstanceDisabled: "
2226  "subkey could not be created. %lx\n", status));
2227  LEAVE;
2228  }
2229 
2230  //
2231  // Default to not changing autorun behavior, based upon setting
2232  // registryValue to zero.
2233  //
2234 
2235  for (i=0;i<2;i++) {
2236 
2237  RtlZeroMemory(&queryTable[0], sizeof(queryTable));
2238 
2239  queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
2240  queryTable[0].DefaultType = REG_DWORD;
2241  queryTable[0].DefaultLength = 0;
2242 
2243  if (i==0) {
2245  queryTable[0].EntryContext = &alwaysDisable;
2246  queryTable[0].DefaultData = &alwaysDisable;
2247  } else {
2249  queryTable[0].EntryContext = &alwaysEnable;
2250  queryTable[0].DefaultData = &alwaysEnable;
2251  }
2252 
2253  //
2254  // don't care if it succeeds, since we set defaults above
2255  //
2256 
2258  (PWSTR)driverParameterHandle,
2259  queryTable,
2260  NULL,
2261  NULL);
2262  }
2263 
2264  } FINALLY {
2265 
2266  if (driverParameterHandle) ZwClose(driverParameterHandle);
2267  if (deviceParameterHandle) ZwClose(deviceParameterHandle);
2268 
2269  }
2270 
2271  if (alwaysEnable && alwaysDisable) {
2272 
2274  "ClassMediaChangeDeviceInstanceDisabled: %s selected\n",
2275  "Both Enable and Disable set -- DISABLE"));
2278  *Enabled = FALSE;
2279 
2280  } else if (alwaysDisable) {
2281 
2283  "ClassMediaChangeDeviceInstanceDisabled: %s selected\n",
2284  "DISABLE"));
2287  *Enabled = FALSE;
2288 
2289  } else if (alwaysEnable) {
2290 
2292  "ClassMediaChangeDeviceInstanceDisabled: %s selected\n",
2293  "ENABLE"));
2296  *Enabled = TRUE;
2297 
2298  } else {
2299 
2301  "ClassMediaChangeDeviceInstanceDisabled: %s selected\n",
2302  "DEFAULT"));
2304 
2305  }
2306 
2307  return status;
2308 
2309 } // end ClasspMediaChangeDeviceInstanceOverride()
2310 
2311 /*++////////////////////////////////////////////////////////////////////////////
2312 
2313 ClasspIsMediaChangeDisabledDueToHardwareLimitation()
2314 
2315 Routine Description:
2316 
2317  The key AutoRunAlwaysDisable contains a MULTI_SZ of hardware IDs for
2318  which to never enable MediaChangeNotification.
2319 
2320  The user can override the global setting to enable or disable Autorun on a
2321  specific cdrom device via the control panel.
2322 
2323 Arguments:
2324 
2325  FdoExtension -
2326  RegistryPath - pointer to the unicode string inside
2327  ...\CurrentControlSet\Services\Cdrom
2328 
2329 Return Value:
2330 
2331  TRUE - no autorun.
2332  FALSE - Autorun may be enabled
2333 
2334 --*/
2335 BOOLEAN
2336 NTAPI
2340  )
2341 {
2342  PSTORAGE_DEVICE_DESCRIPTOR deviceDescriptor = FdoExtension->DeviceDescriptor;
2343  OBJECT_ATTRIBUTES objectAttributes;
2344  HANDLE serviceKey = NULL;
2345  RTL_QUERY_REGISTRY_TABLE parameters[2];
2346 
2347  UNICODE_STRING deviceUnicodeString;
2348  ANSI_STRING deviceString;
2349  ULONG mediaChangeNotificationDisabled = FALSE;
2350 
2351  NTSTATUS status;
2352 
2353 
2354  PAGED_CODE();
2355 
2356  //
2357  // open the service key.
2358  //
2359 
2360  InitializeObjectAttributes(&objectAttributes,
2361  RegistryPath,
2363  NULL,
2364  NULL);
2365 
2366  status = ZwOpenKey(&serviceKey,
2367  KEY_READ,
2368  &objectAttributes);
2369 
2371 
2372 
2373  if(!NT_SUCCESS(status)) {
2374 
2375  //
2376  // always take the safe path. if we can't open the service key,
2377  // disable autorun
2378  //
2379 
2380  return TRUE;
2381 
2382  }
2383 
2384  TRY {
2385  //
2386  // Determine if drive is in a list of those requiring
2387  // autorun to be disabled. this is stored in a REG_MULTI_SZ
2388  // named AutoRunAlwaysDisable. this is required as some autochangers
2389  // must load the disc to reply to ChkVerify request, causing them
2390  // to cycle discs continuously.
2391  //
2392 
2393  PWSTR nullMultiSz;
2394  PCSTR vendorId;
2395  PCSTR productId;
2396  PCSTR revisionId;
2397  ULONG length;
2398  ULONG offset;
2399 
2400  deviceString.Buffer = NULL;
2401  deviceUnicodeString.Buffer = NULL;
2402 
2403  //
2404  // there may be nothing to check against
2405  //
2406 
2407  if ((deviceDescriptor->VendorIdOffset == 0) &&
2408  (deviceDescriptor->ProductIdOffset == 0)) {
2409  LEAVE;
2410  }
2411 
2412  length = 0;
2413 
2414  if (deviceDescriptor->VendorIdOffset == 0) {
2415  vendorId = NULL;
2416  } else {
2417  vendorId = (PCSTR) deviceDescriptor + deviceDescriptor->VendorIdOffset;
2418  length = strlen(vendorId);
2419  }
2420 
2421  if ( deviceDescriptor->ProductIdOffset == 0 ) {
2422  productId = NULL;
2423  } else {
2424  productId = (PCSTR) deviceDescriptor + deviceDescriptor->ProductIdOffset;
2425  length += strlen(productId);
2426  }
2427 
2428  if ( deviceDescriptor->ProductRevisionOffset == 0 ) {
2429  revisionId = NULL;
2430  } else {
2431  revisionId = (PCSTR) deviceDescriptor + deviceDescriptor->ProductRevisionOffset;
2432  length += strlen(revisionId);
2433  }
2434 
2435  //
2436  // allocate a buffer for the string
2437  //
2438 
2439  deviceString.Length = (USHORT)( length );
2440  deviceString.MaximumLength = deviceString.Length + 1;
2441  deviceString.Buffer = ExAllocatePoolWithTag( NonPagedPool,
2442  deviceString.MaximumLength,
2444  );
2445  if (deviceString.Buffer == NULL) {
2447  "ClassMediaChangeDisabledForHardware: Unable to alloc "
2448  "string buffer\n" ));
2449  LEAVE;
2450  }
2451 
2452  //
2453  // copy strings to the buffer
2454  //
2455  offset = 0;
2456 
2457  if (vendorId != NULL) {
2458  RtlCopyMemory(deviceString.Buffer + offset,
2459  vendorId,
2460  strlen(vendorId));
2461  offset += strlen(vendorId);
2462  }
2463 
2464  if ( productId != NULL ) {
2465  RtlCopyMemory(deviceString.Buffer + offset,
2466  productId,
2467  strlen(productId));
2468  offset += strlen(productId);
2469  }
2470  if ( revisionId != NULL ) {
2471  RtlCopyMemory(deviceString.Buffer + offset,
2472  revisionId,
2473  strlen(revisionId));
2474  offset += strlen(revisionId);
2475  }
2476 
2477  ASSERT(offset == deviceString.Length);
2478 
2479  deviceString.Buffer[deviceString.Length] = '\0'; // Null-terminated
2480 
2481  //
2482  // convert to unicode as registry deals with unicode strings
2483  //
2484 
2485  status = RtlAnsiStringToUnicodeString( &deviceUnicodeString,
2486  &deviceString,
2487  TRUE
2488  );
2489  if (!NT_SUCCESS(status)) {
2491  "ClassMediaChangeDisabledForHardware: cannot convert "
2492  "to unicode %lx\n", status));
2493  LEAVE;
2494  }
2495 
2496  //
2497  // query the value, setting valueFound to true if found
2498  //
2499 
2500  RtlZeroMemory(parameters, sizeof(parameters));
2501 
2502  nullMultiSz = L"\0";
2504  parameters[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
2505  parameters[0].Name = L"AutoRunAlwaysDisable";
2506  parameters[0].EntryContext = &mediaChangeNotificationDisabled;
2507  parameters[0].DefaultType = REG_MULTI_SZ;
2508  parameters[0].DefaultData = nullMultiSz;
2509  parameters[0].DefaultLength = 0;
2510 
2512  serviceKey,
2513  parameters,
2514  &deviceUnicodeString,
2515  NULL);
2516 
2517  if ( !NT_SUCCESS(status) ) {
2518  LEAVE;
2519  }
2520 
2521  } FINALLY {
2522 
2523  if (deviceString.Buffer != NULL) {
2524  ExFreePool( deviceString.Buffer );
2525  }
2526  if (deviceUnicodeString.Buffer != NULL) {
2527  RtlFreeUnicodeString( &deviceUnicodeString );
2528  }
2529 
2530  ZwClose(serviceKey);
2531  }
2532 
2533  if (mediaChangeNotificationDisabled) {
2534  DebugPrint((ClassDebugMCN, "ClassMediaChangeDisabledForHardware: "
2535  "Device is on disable list\n"));
2536  return TRUE;
2537  }
2538  return FALSE;
2539 
2540 } // end ClasspIsMediaChangeDisabledDueToHardwareLimitation()
2541 
2542 /*++////////////////////////////////////////////////////////////////////////////
2543 
2544 ClasspIsMediaChangeDisabledForClass()
2545 
2546 Routine Description:
2547 
2548  The user must specify that AutoPlay is to run on the platform
2549  by setting the registry value HKEY_LOCAL_MACHINE\System\CurrentControlSet\
2550  Services<SERVICE>\Autorun:REG_DWORD:1.
2551 
2552  The user can override the global setting to enable or disable Autorun on a
2553  specific cdrom device via the control panel.
2554 
2555 Arguments:
2556 
2557  FdoExtension -
2558  RegistryPath - pointer to the unicode string inside
2559  ...\CurrentControlSet\Services\Cdrom
2560 
2561 Return Value:
2562 
2563  TRUE - Autorun is disabled for this class
2564  FALSE - Autorun is enabled for this class
2565 
2566 --*/
2567 BOOLEAN
2568 NTAPI
2572  )
2573 {
2574  //PSTORAGE_DEVICE_DESCRIPTOR deviceDescriptor = FdoExtension->DeviceDescriptor;
2575 
2576  OBJECT_ATTRIBUTES objectAttributes;
2577  HANDLE serviceKey = NULL;
2578  HANDLE parametersKey = NULL;
2579  RTL_QUERY_REGISTRY_TABLE parameters[3];
2580 
2581  UNICODE_STRING paramStr;
2582  //UNICODE_STRING deviceUnicodeString;
2583  //ANSI_STRING deviceString;
2584 
2585  //
2586  // Default to ENABLING MediaChangeNotification (!)
2587  //
2588 
2589  ULONG mcnRegistryValue = 1;
2590 
2591  NTSTATUS status;
2592 
2593 
2594  PAGED_CODE();
2595 
2596  //
2597  // open the service key.
2598  //
2599 
2600  InitializeObjectAttributes(&objectAttributes,
2601  RegistryPath,
2603  NULL,
2604  NULL);
2605 
2606  status = ZwOpenKey(&serviceKey,
2607  KEY_READ,
2608  &objectAttributes);
2609 
2611 
2612  if(!NT_SUCCESS(status)) {
2613 
2614  //
2615  // return the default value, which is the
2616  // inverse of the registry setting default
2617  // since this routine asks if it's disabled
2618  //
2619 
2620  DebugPrint((ClassDebugMCN, "ClassCheckServiceMCN: Defaulting to %s\n",
2621  (mcnRegistryValue ? "Enabled" : "Disabled")));
2622  return (BOOLEAN)(!mcnRegistryValue);
2623 
2624  }
2625 
2626  RtlZeroMemory(parameters, sizeof(parameters));
2627 
2628  //
2629  // Open the parameters key (if any) beneath the services key.
2630  //
2631 
2632  RtlInitUnicodeString(&paramStr, L"Parameters");
2633 
2634  InitializeObjectAttributes(&objectAttributes,
2635  &paramStr,
2637  serviceKey,
2638  NULL);
2639 
2640  status = ZwOpenKey(&parametersKey,
2641  KEY_READ,
2642  &objectAttributes);
2643 
2644  if (!NT_SUCCESS(status)) {
2645  parametersKey = NULL;
2646  }
2647 
2648 
2649 
2650  //
2651  // Check for the Autorun value.
2652  //
2653 
2654  parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
2655  parameters[0].Name = L"Autorun";
2656  parameters[0].EntryContext = &mcnRegistryValue;
2657  parameters[0].DefaultType = REG_DWORD;
2658  parameters[0].DefaultData = &mcnRegistryValue;
2659  parameters[0].DefaultLength = sizeof(ULONG);
2660 
2662  serviceKey,
2663  parameters,
2664  NULL,
2665  NULL);
2666 
2667  DebugPrint((ClassDebugMCN, "ClassCheckServiceMCN: "
2668  "<Service>/Autorun flag = %d\n", mcnRegistryValue));
2669 
2670  if(parametersKey != NULL) {
2671 
2673  parametersKey,
2674  parameters,
2675  NULL,
2676  NULL);
2677  DebugPrint((ClassDebugMCN, "ClassCheckServiceMCN: "
2678  "<Service>/Parameters/Autorun flag = %d\n",
2679  mcnRegistryValue));
2680  ZwClose(parametersKey);
2681 
2682  }
2683  ZwClose(serviceKey);
2684 
2685  DebugPrint((ClassDebugMCN, "ClassCheckServiceMCN: "
2686  "Autoplay for device %p is %s\n",
2687  FdoExtension->DeviceObject,
2688  (mcnRegistryValue ? "on" : "off")
2689  ));
2690 
2691  //
2692  // return if it is _disabled_, which is the
2693  // inverse of the registry setting
2694  //
2695 
2696  return (BOOLEAN)(!mcnRegistryValue);
2697 } // end ClasspIsMediaChangeDisabledForClass()
2698 
2699 /*++////////////////////////////////////////////////////////////////////////////
2700 
2701 ClassEnableMediaChangeDetection() ISSUE-2000/02/20-henrygab - why public?
2702 ClassEnableMediaChangeDetection() ISSUE-2000/02/20-henrygab - not documented
2703 
2704 Routine Description:
2705 
2706  This routine
2707 
2708 Arguments:
2709 
2710  DeviceObject -
2711  Irp -
2712 
2713 Return Value:
2714 
2715 --*/
2716 VOID
2717 NTAPI
2720  )
2721 {
2722  PMEDIA_CHANGE_DETECTION_INFO info = FdoExtension->MediaChangeDetectionInfo;
2723  LONG oldCount;
2724 
2725  PAGED_CODE();
2726 
2727  if(info == NULL) {
2729  "ClassEnableMediaChangeDetection: not initialized\n"));
2730  return;
2731  }
2732 
2733  KeWaitForMutexObject(&info->MediaChangeMutex,
2734  UserRequest,
2735  KernelMode,
2736  FALSE,
2737  NULL);
2738 
2739  oldCount = --info->MediaChangeDetectionDisableCount;
2740 
2741  ASSERT(oldCount >= 0);
2742 
2743  DebugPrint((ClassDebugMCN, "ClassEnableMediaChangeDetection: Disable count "
2744  "reduced to %d - ",
2745  info->MediaChangeDetectionDisableCount));
2746 
2747  if(oldCount == 0) {
2748 
2749  //
2750  // We don't know what state the media is in anymore.
2751  //
2752 
2754  MediaUnknown,
2755  FALSE
2756  );
2757 
2758  //
2759  // Reset the MCN timer.
2760  //
2761 
2763 
2764  DebugPrint((ClassDebugMCN, "MCD is enabled\n"));
2765 
2766  } else {
2767 
2768  DebugPrint((ClassDebugMCN, "MCD still disabled\n"));
2769 
2770  }
2771 
2772 
2773  //
2774  // Let something else run.
2775  //
2776 
2777  KeReleaseMutex(&info->MediaChangeMutex, FALSE);
2778 
2779  return;
2780 } // end ClassEnableMediaChangeDetection()
2781 
2782 /*++////////////////////////////////////////////////////////////////////////////
2783 
2784 ClassDisableMediaChangeDetection() ISSUE-2000/02/20-henrygab - why public?
2785 ClassDisableMediaChangeDetection() ISSUE-2000/02/20-henrygab - not documented
2786 
2787 Routine Description:
2788 
2789  This routine
2790 
2791 Arguments:
2792 
2793  DeviceObject -
2794  Irp -
2795 
2796 Return Value:
2797 
2798 --*/
2800 
2801 VOID
2802 NTAPI
2805  )
2806 {
2807  PMEDIA_CHANGE_DETECTION_INFO info = FdoExtension->MediaChangeDetectionInfo;
2808 
2809  PAGED_CODE();
2810 
2811  if(info == NULL) {
2812  return;
2813  }
2814 
2815  KeWaitForMutexObject(&info->MediaChangeMutex,
2816  UserRequest,
2817  KernelMode,
2818  FALSE,
2819  NULL);
2820 
2821  info->MediaChangeDetectionDisableCount++;
2822 
2823  DebugPrint((ClassDebugMCN, "ClassDisableMediaChangeDetection: "
2824  "disable count is %d\n",
2825  info->MediaChangeDetectionDisableCount));
2826 
2827  KeReleaseMutex(&info->MediaChangeMutex, FALSE);
2828 
2829  return;
2830 } // end ClassDisableMediaChangeDetection()
2831 
2832 /*++////////////////////////////////////////////////////////////////////////////
2833 
2834 ClassCleanupMediaChangeDetection() ISSUE-2000/02/20-henrygab - why public?!
2835 
2836 Routine Description:
2837 
2838  This routine will cleanup any resources allocated for MCN. It is called
2839  by classpnp during remove device, and therefore is not typically required
2840  by external drivers.
2841 
2842 Arguments:
2843 
2844 Return Value:
2845 
2846 --*/
2847 VOID
2848 NTAPI
2851  )
2852 {
2853  PMEDIA_CHANGE_DETECTION_INFO info = FdoExtension->MediaChangeDetectionInfo;
2854 
2855  PAGED_CODE()
2856 
2857  if(info == NULL) {
2858  return;
2859  }
2860 
2861  FdoExtension->MediaChangeDetectionInfo = NULL;
2862 
2863  if (info->Gesn.Buffer) {
2864  ExFreePool(info->Gesn.Buffer);
2865  }
2866  IoFreeIrp(info->MediaChangeIrp);
2867  ExFreePool(info->SenseBuffer);
2868  ExFreePool(info);
2869  return;
2870 } // end ClassCleanupMediaChangeDetection()
2871 
2872 /*++////////////////////////////////////////////////////////////////////////////
2873 
2874 ClasspMcnControl() - ISSUE-2000/02/20-henrygab - not documented
2875 
2876 Routine Description:
2877 
2878  This routine
2879 
2880 Arguments:
2881 
2882  DeviceObject -
2883  Irp -
2884 
2885 Return Value:
2886 
2887 --*/
2888 NTSTATUS
2889 NTAPI
2892  IN PIRP Irp,
2894  )
2895 {
2896  PCOMMON_DEVICE_EXTENSION commonExtension =
2898 
2900  PPREVENT_MEDIA_REMOVAL request = Irp->AssociatedIrp.SystemBuffer;
2901 
2902  PFILE_OBJECT fileObject = irpStack->FileObject;
2903  PFILE_OBJECT_EXTENSION fsContext = NULL;
2904 
2906 
2907  PAGED_CODE();
2908 
2909  //
2910  // Check to make sure we have a file object extension to keep track of this
2911  // request. If not we'll fail it before synchronizing.
2912  //
2913 
2914  TRY {
2915 
2916  if(fileObject != NULL) {
2917  fsContext = ClasspGetFsContext(commonExtension, fileObject);
2918  }else if(Irp->RequestorMode == KernelMode) { // && fileObject == NULL
2919  fsContext = &FdoExtension->KernelModeMcnContext;
2920  }
2921 
2922  if (fsContext == NULL) {
2923 
2924  //
2925  // This handle isn't setup correctly. We can't let the
2926  // operation go.
2927  //
2928 
2930  LEAVE;
2931  }
2932 
2933  if(request->PreventMediaRemoval) {
2934 
2935  //
2936  // This is a lock command. Reissue the command in case bus or
2937  // device was reset and the lock was cleared.
2938  //
2939 
2942 
2943  } else {
2944 
2945  if(fsContext->McnDisableCount == 0) {
2947  LEAVE;
2948  }
2949 
2952  }
2953 
2954  } FINALLY {
2955 
2956  Irp->IoStatus.Status = status;
2957 
2958  if(Srb) {
2959  ExFreePool(Srb);
2960  }
2961 
2962  ClassReleaseRemoveLock(FdoExtension->DeviceObject, Irp);
2963  ClassCompleteRequest(FdoExtension->DeviceObject,
2964  Irp,
2965  IO_NO_INCREMENT);
2966  }
2967  return status;
2968 } // end ClasspMcnControl(
2969 
2970 /*++////////////////////////////////////////////////////////////////////////////
2971 
2972 ClasspMediaChangeRegistryCallBack()
2973 
2974 Routine Description:
2975 
2976  This callback for a registry SZ or MULTI_SZ is called once for each
2977  SZ in the value. It will attempt to match the data with the
2978  UNICODE_STRING passed in as Context, and modify EntryContext if a
2979  match is found. Written for ClasspCheckRegistryForMediaChangeCompletion
2980 
2981 Arguments:
2982 
2983  ValueName - name of the key that was opened
2984  ValueType - type of data stored in the value (REG_SZ for this routine)
2985  ValueData - data in the registry, in this case a wide string
2986  ValueLength - length of the data including the terminating null
2987  Context - unicode string to compare against ValueData
2988  EntryContext - should be initialized to 0, will be set to 1 if match found
2989 
2990 Return Value:
2991 
2992  STATUS_SUCCESS
2993  EntryContext will be 1 if found
2994 
2995 --*/
2996 NTSTATUS
2997 NTAPI
2999  IN PWSTR ValueName,
3000  IN ULONG ValueType,
3001  IN PVOID ValueData,
3003  IN PVOID Context,
3005  )
3006 {
3007  PULONG valueFound;
3008  PUNICODE_STRING deviceString;
3009  PWSTR keyValue;
3010 
3011  PAGED_CODE();
3013 
3014 
3015  //
3016  // if we have already set the value to true, exit
3017  //
3018 
3019  valueFound = EntryContext;
3020  if ((*valueFound) != 0) {
3021  DebugPrint((ClassDebugMCN, "ClasspMcnRegCB: already set to true\n"));
3022  return STATUS_SUCCESS;
3023  }
3024 
3025  if (ValueLength == sizeof(WCHAR)) {
3026  DebugPrint((ClassDebugError, "ClasspMcnRegCB: NULL string should "
3027  "never be passed to registry call-back!\n"));
3028  return STATUS_SUCCESS;
3029  }
3030 
3031 
3032  //
3033  // if the data is not a terminated string, exit
3034  //
3035 
3036  if (ValueType != REG_SZ) {
3037  return STATUS_SUCCESS;
3038  }
3039 
3040  deviceString = Context;
3041  keyValue = ValueData;
3042  ValueLength -= sizeof(WCHAR); // ignore the null character
3043 
3044  //
3045  // do not compare more memory than is in deviceString
3046  //
3047 
3048  if (ValueLength > deviceString->Length) {
3049  ValueLength = deviceString->Length;
3050  }
3051 
3052  //
3053  // if the strings match, disable autorun
3054  //
3055 
3056  if (RtlCompareMemory(deviceString->Buffer, keyValue, ValueLength) == ValueLength) {
3057  DebugPrint((ClassDebugMCN, "ClasspRegMcnCB: Match found\n"));
3058  DebugPrint((ClassDebugMCN, "ClasspRegMcnCB: DeviceString at %p\n",
3059  deviceString->Buffer));
3060  DebugPrint((ClassDebugMCN, "ClasspRegMcnCB: KeyValue at %p\n",
3061  keyValue));
3062  (*valueFound) = TRUE;
3063  }
3064 
3065  return STATUS_SUCCESS;
3066 } // end ClasspMediaChangeRegistryCallBack()
3067 
3068 /*++////////////////////////////////////////////////////////////////////////////
3069 
3070 ClasspTimerTick() - ISSUE-2000/02/20-henrygab - not documented
3071 
3072 Routine Description:
3073 
3074  This routine
3075 
3076 Arguments:
3077 
3078  DeviceObject -
3079  Irp -
3080 
3081 Return Value:
3082 
3083 --*/
3084 VOID
3085 NTAPI
3088  PVOID Context
3089  )
3090 {
3093  ULONG isRemoved;
3094 
3095  ASSERT(commonExtension->IsFdo);
3096 
3097  //
3098  // Do any media change work
3099  //
3101 
3102  //
3103  // We stop the timer before deleting the device. It's safe to keep going
3104  // if the flag value is REMOVE_PENDING because the removal thread will be
3105  // blocked trying to stop the timer.
3106  //
3107 
3108  ASSERT(isRemoved != REMOVE_COMPLETE);
3109 
3110  //
3111  // This routine is reasonably safe even if the device object has a pending
3112  // remove
3113 
3114  if(!isRemoved) {
3115 
3117 
3118  //
3119  // Do any media change detection work
3120  //
3121 
3122  if (fdoExtension->MediaChangeDetectionInfo != NULL) {
3123 
3124  ClassCheckMediaState(fdoExtension);
3125 
3126  }
3127 
3128  //
3129  // Do any failure prediction work
3130  //
3131  if ((info != NULL) && (info->Method != FailurePredictionNone)) {
3132 
3133  ULONG countDown;
3134  //ULONG active;
3135 
3136  if (ClasspCanSendPollingIrp(fdoExtension)) {
3137 
3138  //
3139  // Synchronization is not required here since the Interlocked
3140  // locked instruction guarantees atomicity. Other code that
3141  // resets CountDown uses InterlockedExchange which is also
3142  // atomic.
3143  //
3144  countDown = InterlockedDecrement((PLONG)&info->CountDown);
3145  if (countDown == 0) {
3146 
3147  DebugPrint((4, "ClasspTimerTick: Send FP irp for %p\n",
3148  DeviceObject));
3149 
3150  if(info->WorkQueueItem == NULL) {
3151 
3152  info->WorkQueueItem =
3153  IoAllocateWorkItem(fdoExtension->DeviceObject);
3154 
3155  if(info->WorkQueueItem == NULL) {
3156 
3157  //
3158  // Set the countdown to one minute in the future.
3159  // we'll try again then in the hopes there's more
3160  // free memory.
3161  //
3162 
3163  DebugPrint((1, "ClassTimerTick: Couldn't allocate "
3164  "item - try again in one minute\n"));
3165  InterlockedExchange((PLONG)&info->CountDown, 60);
3166 
3167  } else {
3168 
3169  //
3170  // Grab the remove lock so that removal will block
3171  // until the work item is done.
3172  //
3173 
3174  ClassAcquireRemoveLock(fdoExtension->DeviceObject,
3175  info->WorkQueueItem);
3176 
3177  IoQueueWorkItem(info->WorkQueueItem,
3180  info);
3181  }
3182 
3183  } else {
3184 
3185  DebugPrint((3, "ClasspTimerTick: Failure "
3186  "Prediction work item is "
3187  "already active for device %p\n",
3188  DeviceObject));
3189 
3190  }
3191  } // end (countdown == 0)
3192 
3193  } else {
3194  //
3195  // If device is sleeping then just rearm polling timer
3196  DebugPrint((4, "ClassTimerTick, SHHHH!!! device is %p is sleeping\n",
3197  DeviceObject));
3198  }
3199 
3200  } // end failure prediction polling
3201 
3202  //
3203  // Give driver a chance to do its own specific work
3204  //
3205 
3206  if (commonExtension->DriverExtension->InitData.ClassTick != NULL) {
3207 
3208  commonExtension->DriverExtension->InitData.ClassTick(DeviceObject);
3209 
3210  } // end device specific tick handler
3211  } // end check for removed
3212 
3214 } // end ClasspTimerTick()
3215 
3216 /*++////////////////////////////////////////////////////////////////////////////
3217 
3218 ClasspEnableTimer() - ISSUE-2000/02/20-henrygab - not documented
3219 
3220 Routine Description:
3221 
3222  This routine
3223 
3224 Arguments:
3225 
3226  DeviceObject -
3227  Irp -
3228 
3229 Return Value:
3230 
3231 --*/
3232 NTSTATUS
3233 NTAPI
3236  )
3237 {
3238  NTSTATUS status;
3239 
3240  PAGED_CODE();
3241 
3242  if (DeviceObject->Timer == NULL) {
3243 
3245 
3246  } else {
3247 
3249 
3250  }
3251 
3252  if (NT_SUCCESS(status)) {
3253 
3255  DebugPrint((1, "ClasspEnableTimer: Once a second timer enabled "
3256  "for device %p\n", DeviceObject));
3257 
3258  }
3259 
3260  DebugPrint((1, "ClasspEnableTimer: Device %p, Status %lx "
3261  "initializing timer\n", DeviceObject, status));
3262 
3263  return status;
3264 
3265 } // end ClasspEnableTimer()
3266 
3267 /*++////////////////////////////////////////////////////////////////////////////
3268 
3269 ClasspDisableTimer() - ISSUE-2000/02/20-henrygab - not documented
3270 
3271 Routine Description:
3272 
3273  This routine
3274 
3275 Arguments:
3276 
3277  DeviceObject -
3278  Irp -
3279 
3280 Return Value:
3281 
3282 --*/
3283 NTSTATUS
3284 NTAPI
3287  )
3288 {
3289  //PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
3290  //PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
3291  //PMEDIA_CHANGE_DETECTION_INFO mCDInfo = fdoExtension->MediaChangeDetectionInfo;
3292  //PFAILURE_PREDICTION_INFO fPInfo = fdoExtension->FailurePredictionInfo;
3293  //NTSTATUS status;
3294 
3295  PAGED_CODE();
3296 
3297  if (DeviceObject->Timer != NULL) {
3298 
3299  //
3300  // we are only going to stop the actual timer in remove device routine.
3301  // it is the responsibility of the code within the timer routine to
3302  // check if the device is removed and not processing io for the final
3303  // call.
3304  // this keeps the code clean and prevents lots of bugs.
3305  //
3306 
3307 
3309  DebugPrint((3, "ClasspDisableTimer: Once a second timer disabled "
3310  "for device %p\n", DeviceObject));
3311 
3312  } else {
3313 
3314  DebugPrint((1, "ClasspDisableTimer: Timer never enabled\n"));
3315 
3316  }
3317 
3318  return STATUS_SUCCESS;
3319 } // end ClasspDisableTimer()
3320 
3321 /*++////////////////////////////////////////////////////////////////////////////
3322 
3323 ClasspFailurePredict() - ISSUE-2000/02/20-henrygab - not documented
3324 
3325 Routine Description:
3326 
3327  This routine
3328 
3329 Arguments:
3330 
3331  DeviceObject -
3332  Irp -
3333 
3334 Return Value:
3335 
3336 Note: this function can be called (via the workitem callback) after the paging device is shut down,
3337  so it must be PAGE LOCKED.
3338 --*/
3339 VOID
3340 NTAPI
3343  IN PVOID Context
3344  )
3345 {
3348  PIO_WORKITEM workItem;
3349  STORAGE_PREDICT_FAILURE checkFailure;
3350  SCSI_ADDRESS scsiAddress;
3351 
3352  NTSTATUS status;
3353 
3354  ASSERT(info != NULL);
3355 
3356  DebugPrint((1, "ClasspFailurePredict: Polling for failure\n"));
3357 
3358  //
3359  // Mark the work item as inactive and reset the countdown timer. we
3360  // can't risk freeing the work item until we've released the remove-lock
3361  // though - if we do it might get resused as a tag before we can release
3362  // the lock.
3363  //
3364 
3365  InterlockedExchange((PLONG)&info->CountDown, info->Period);
3366  workItem = InterlockedExchangePointer((PVOID*)&info->WorkQueueItem, NULL);
3367 
3368  if (ClasspCanSendPollingIrp(fdoExtension)) {
3369 
3370  KEVENT event;
3371  PDEVICE_OBJECT topOfStack;
3372  PIRP irp = NULL;
3373  IO_STATUS_BLOCK ioStatus;
3374 
3376 
3378 
3379  //
3380  // Send down irp to see if drive is predicting failure
3381  //
3382 
3385  topOfStack,
3386  NULL,
3387  0,
3388  &checkFailure,
3389  sizeof(STORAGE_PREDICT_FAILURE),
3390  FALSE,
3391  &event,
3392  &ioStatus);
3393 
3394 
3395  if (irp != NULL) {
3396  status = IoCallDriver(topOfStack, irp);
3397  if (status == STATUS_PENDING) {
3399  status = ioStatus.Status;
3400  }
3401  } else {
3403  }
3404 
3405  if (NT_SUCCESS(status) && (checkFailure.PredictFailure)) {
3406 
3407  checkFailure.PredictFailure = 512;
3408 
3409  //
3410  // Send down irp to get scsi address
3411  //
3413 
3414  RtlZeroMemory(&scsiAddress, sizeof(SCSI_ADDRESS));
3417  topOfStack,
3418  NULL,
3419  0,
3420  &scsiAddress,
3421  sizeof(SCSI_ADDRESS),
3422  FALSE,
3423  &event,
3424  &ioStatus);
3425 
3426  if (irp != NULL) {
3427  status = IoCallDriver(topOfStack, irp);
3428  if (status == STATUS_PENDING) {
3430  status = ioStatus.Status;
3431  }
3432  }
3433 
3434  ClassNotifyFailurePredicted(fdoExtension,
3435  (PUCHAR)&checkFailure,
3436  sizeof(checkFailure),
3437  (BOOLEAN)(fdoExtension->FailurePredicted == FALSE),
3438  2,
3439  scsiAddress.PathId,
3440  scsiAddress.TargetId,
3441  scsiAddress.Lun);
3442 
3443  fdoExtension->FailurePredicted = TRUE;
3444 
3445  }
3446 
3447  ObDereferenceObject(topOfStack);
3448  }
3449 
3451  IoFreeWorkItem(workItem);
3452  return;
3453 } // end ClasspFailurePredict()
3454 
3455 /*++////////////////////////////////////////////////////////////////////////////
3456 
3457 ClassNotifyFailurePredicted() ISSUE-alanwar-2000/02/20 - not documented
3458 
3459 Routine Description:
3460 
3461 Arguments:
3462 
3463 Return Value:
3464 
3465 --*/
3466 VOID
3467 NTAPI
3470  PUCHAR Buffer,
3471  ULONG BufferSize,
3472  BOOLEAN LogError,
3474  UCHAR PathId,
3475  UCHAR TargetId,
3476  UCHAR Lun
3477  )
3478 {
3479  PIO_ERROR_LOG_PACKET logEntry;
3480 
3481  DebugPrint((1, "ClasspFailurePredictPollCompletion: Failure predicted for device %p\n", FdoExtension->DeviceObject));
3482 
3483  //
3484  // Fire off a WMI event
3485  //
3486  ClassWmiFireEvent(FdoExtension->DeviceObject,
3488  0,
3489  BufferSize,
3490  Buffer);
3491 
3492  //
3493  // Log an error into the eventlog
3494  //
3495 
3496  if (LogError)
3497  {
3498  logEntry = IoAllocateErrorLogEntry(
3499  FdoExtension->DeviceObject,
3500  sizeof(IO_ERROR_LOG_PACKET) + (3 * sizeof(ULONG)));
3501 
3502  if (logEntry != NULL)
3503  {
3504 
3505  logEntry->FinalStatus = STATUS_SUCCESS;
3506  logEntry->ErrorCode = IO_WRN_FAILURE_PREDICTED;
3507  logEntry->SequenceNumber = 0;
3510  logEntry->RetryCount = 0;
3511  logEntry->UniqueErrorValue = UniqueErrorValue;
3512  logEntry->DumpDataSize = 3;
3513 
3514  logEntry->DumpData[0] = PathId;
3515  logEntry->DumpData[1] = TargetId;
3516  logEntry->DumpData[2] = Lun;
3517 
3518  //
3519  // Write the error log packet.
3520  //
3521 
3522  IoWriteErrorLogEntry(logEntry);
3523  }
3524  }
3525 } // end ClassNotifyFailurePredicted()
3526 
3527 /*++////////////////////////////////////////////////////////////////////////////
3528 
3529 ClassSetFailurePredictionPoll()
3530 
3531 Routine Description:
3532 
3533  This routine enables polling for failure prediction, setting the timer
3534  to fire every N seconds as specified by the PollingPeriod.
3535 
3536 Arguments:
3537 
3538  FdoExtension - the device to setup failure prediction for.
3539 
3540  FailurePredictionMethod - specific failure prediction method to use
3541  if set to FailurePredictionNone, will disable failure detection
3542 
3543  PollingPeriod - if 0 then no change to current polling timer
3544 
3545 Return Value:
3546 
3547  NT Status
3548 
3549 --*/
3550 NTSTATUS
3551 NTAPI
3556  )
3557 {
3559  NTSTATUS status;
3560  //DEVICE_POWER_STATE powerState;
3561 
3562  PAGED_CODE();
3563 
3564  if (FdoExtension->FailurePredictionInfo == NULL) {
3565 
3567 
3569  sizeof(FAILURE_PREDICTION_INFO),
3571 
3572  if (info == NULL) {
3573 
3575 
3576  }
3577 
3579 
3580  info->WorkQueueItem = NULL;
3582 
3583  } else {
3584 
3585  //
3586  // FaultPrediction has not been previously initialized, nor
3587  // is it being initialized now. No need to do anything.
3588  //
3589  return STATUS_SUCCESS;
3590 
3591  }
3592 
3593  FdoExtension->FailurePredictionInfo = info;
3594 
3595  } else {
3596 
3597  info = FdoExtension->FailurePredictionInfo;
3598 
3599  }
3600 
3601  KeWaitForSingleObject(&info->Event,
3602  UserRequest,
3603  UserMode,
3604  FALSE,
3605  NULL);
3606 
3607 
3608  //
3609  // Reset polling period and counter. Setup failure detection type
3610  //
3611 
3612  if (PollingPeriod != 0) {
3613 
3615 
3616  }
3617 
3618  InterlockedExchange((PLONG)&info->CountDown, info->Period);
3619 
3620  info->Method = FailurePredictionMethod;
3622 
3623  status = ClasspEnableTimer(FdoExtension->DeviceObject);
3624 
3625  if (NT_SUCCESS(status)) {
3626  DebugPrint((3, "ClassEnableFailurePredictPoll: Enabled for "
3627  "device %p\n", FdoExtension->DeviceObject));
3628  }
3629 
3630  } else {
3631 
3632  status = ClasspDisableTimer(FdoExtension->DeviceObject);
3633  DebugPrint((3, "ClassEnableFailurePredictPoll: Disabled for "
3634  "device %p\n", FdoExtension->DeviceObject));
3636 
3637  }
3638 
3639  KeSetEvent(&info->Event, IO_NO_INCREMENT, FALSE);
3640 
3641  return status;
3642 } // end ClassSetFailurePredictionPoll()
UCHAR PathId
Definition: scsi_port.h:149
#define KeQuerySystemTime(t)
Definition: env_spec_w32.h:570
_In_ ULONG _In_ BOOLEAN _In_ ULONG UniqueErrorValue
Definition: classpnp.h:1117
NTSTATUS NTAPI ClasspInitializePolling(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, IN BOOLEAN AllowDriveToSleep)
Definition: autorun.c:1487
#define NOTIFICATION_NO_CLASS_EVENTS
Definition: scsi.h:42
PFILE_OBJECT_EXTENSION NTAPI ClasspGetFsContext(IN PCOMMON_DEVICE_EXTENSION CommonExtension, IN PFILE_OBJECT FileObject)
Definition: create.c:969
#define FINALLY
Definition: classpnp.h:113
#define SRB_STATUS_BUS_RESET
Definition: srb.h:345
VOID NTAPI ClassDisableMediaChangeDetection(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension)
Definition: autorun.c:2803
UCHAR SenseKey
Definition: cdrw_hw.h:1167
#define IN
Definition: typedefs.h:38
NTSTATUS NTAPI ClasspEnableTimer(PDEVICE_OBJECT DeviceObject)
Definition: autorun.c:3234
enum _MEDIA_CHANGE_DETECTION_STATE MEDIA_CHANGE_DETECTION_STATE
#define TRUE
Definition: types.h:120
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
* PSTORAGE_ADAPTER_DESCRIPTOR
Definition: ntddstor.h:476
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
#define IOCTL_SCSI_GET_ADDRESS
Definition: scsi_port.h:52
#define ClassAcquireRemoveLock(devobj, tag)
Definition: classpnp.h:97
ULONG SrbFlags
Definition: srb.h:252
_In_ ULONG _In_ BOOLEAN _In_ ULONG _In_ UCHAR _In_ UCHAR _In_ UCHAR Lun
Definition: classpnp.h:1117
#define SCSIOP_GET_EVENT_STATUS
Definition: cdrw_hw.h:934
NTSTATUS NTAPI ClasspMcnControl(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, IN PIRP Irp, IN PSCSI_REQUEST_BLOCK Srb)
Definition: autorun.c:2890
struct _TARGET_DEVICE_CUSTOM_NOTIFICATION TARGET_DEVICE_CUSTOM_NOTIFICATION
PVOID OriginalRequest
Definition: srb.h:258
UCHAR Cdb[16]
Definition: srb.h:271
#define GESN_TIMEOUT_VALUE
Definition: autorun.c:28
USHORT Flags
Definition: iotypes.h:169
#define KeWaitForMutexObject
Definition: kefuncs.h:568
#define STATUS_DATA_OVERRUN
Definition: udferr_usr.h:152
PMEDIA_CHANGE_DETECTION_INFO MediaChangeDetectionInfo
Definition: classpnp.h:721
_In_ ULONG _In_ BOOLEAN LogError
Definition: classpnp.h:1117
VOID NTAPI IoStartTimer(IN PDEVICE_OBJECT DeviceObject)
Definition: iotimer.c:133
#define STATUS_MORE_PROCESSING_REQUIRED
Definition: shellext.h:63
VOID NTAPI ClassNotifyFailurePredicted(PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, PUCHAR Buffer, ULONG BufferSize, BOOLEAN LogError, ULONG UniqueErrorValue, UCHAR PathId, UCHAR TargetId, UCHAR Lun)
Definition: autorun.c:3468
#define REMOVE_COMPLETE
Definition: classpnp.h:95
#define DBGGETADSENSECODESTR(_pSrb)
Definition: debug.h:142
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
#define TEST_FLAG(Flags, Bit)
Definition: classpnp.h:156
_In_ const GUID _In_ ULONG ExtraDataSize
Definition: classpnp.h:1236
#define NOTIFICATION_MEDIA_STATUS_CLASS_MASK
Definition: scsi.h:37
#define MEDIA_CHANGE_TIMEOUT_TIME
Definition: classpnp.h:130
_In_ ULONG _In_ BOOLEAN _In_ ULONG _In_ UCHAR PathId
Definition: classpnp.h:1117
NTSTATUS FinalStatus
Definition: iotypes.h:1965
#define PLUGPLAY_REGKEY_DEVICE
Definition: iofuncs.h:2738
_In_ PIRP Irp
Definition: csq.h:116
#define SRB_FLAGS_NO_QUEUE_FREEZE
Definition: srb.h:396
#define KEY_READ
Definition: nt_native.h:1023
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:323
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
PVOID DataBuffer
Definition: srb.h:255
NTSYSAPI NTSTATUS NTAPI ZwClose(_In_ HANDLE Handle)
uint16_t * PWSTR
Definition: typedefs.h:54
_In_ ULONG _In_ BOOLEAN _In_ ULONG _In_ UCHAR _In_ UCHAR TargetId
Definition: classpnp.h:1117
#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
_In_ PCWSTR _In_z_ PCWSTR _In_ ULONG ValueType
Definition: rtlfuncs.h:4000
#define CLASS_SPECIAL_CAUSE_NOT_REPORTABLE_HACK
Definition: scsi_port.h:175
VOID NTAPI MmBuildMdlForNonPagedPool(IN PMDL Mdl)
Definition: mdlsup.c:428
IO_COMPLETION_ROUTINE ClassSignalCompletion
Definition: classpnp.h:1137
Definition: cdrw_hw.h:28
LONG NTSTATUS
Definition: precomp.h:26
#define SCSIOP_TEST_UNIT_READY
Definition: cdrw_hw.h:866
#define LEAVE
Definition: classpnp.h:112
GLintptr offset
Definition: glext.h:5920
ULONG NTAPI KeQueryTimeIncrement(VOID)
Definition: clock.c:153
#define TRY(sps, bps)
BOOLEAN LoggedTURFailureSinceLastIO
Definition: classp.h:417
#define DO_VERIFY_VOLUME
Definition: env_spec_w32.h:393
BOOLEAN NTAPI ClasspIsMediaChangeDisabledDueToHardwareLimitation(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, IN PUNICODE_STRING RegistryPath)
Definition: autorun.c:2337
#define STATUS_INVALID_DEVICE_REQUEST
Definition: udferr_usr.h:138
#define InterlockedCompareExchange
Definition: interlocked.h:104
VOID NTAPI ClassSendEjectionNotification(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension)
Definition: autorun.c:139
UCHAR CdbLength
Definition: srb.h:250
GLuint buffer
Definition: glext.h:5915
VOID NTAPI ClassSetMediaChangeState(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, IN MEDIA_CHANGE_DETECTION_STATE NewState, IN BOOLEAN Wait)
Definition: autorun.c:780
NTSTATUS NTAPI ClasspMediaChangeDeviceInstanceOverride(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, OUT PBOOLEAN Enabled)
Definition: autorun.c:2165
#define SCSI_ADSENSE_LUN_NOT_READY
Definition: cdrw_hw.h:1218
VOID NTAPI ObDereferenceObject(IN PVOID Object)
Definition: obref.c:375
#define CLASS_TAG_FAILURE_PREDICT
Definition: classpnp.h:84
#define NOTIFICATION_MEDIA_EVENT_MEDIA_CHANGE
Definition: scsi.h:97
UCHAR QueueAction
Definition: srb.h:249
GUID StoragePredictFailureEventGuid
Definition: autorun.c:35
#define MAXIMUM_IMMEDIATE_MCN_RETRIES
Definition: autorun.c:30
#define SRB_FLAGS_DATA_IN
Definition: srb.h:392
UNICODE_STRING RegistryPath
Definition: kbdclass.h:25
LONG NTAPI KeReleaseMutex(IN PKMUTEX Mutex, IN BOOLEAN Wait)
Definition: mutex.c:189
PIO_WORKITEM NTAPI IoAllocateWorkItem(IN PDEVICE_OBJECT DeviceObject)
Definition: iowork.c:75
#define NOTIFICATION_DEVICE_BUSY_CLASS_MASK
Definition: scsi.h:39
ULONG TimeOutValue
Definition: srb.h:254
LONG NTAPI KeSetEvent(IN PKEVENT Event, IN KPRIORITY Increment, IN BOOLEAN Wait)
Definition: eventobj.c:159
#define SCSI_SENSE_NOT_READY
Definition: cdrw_hw.h:1189
NTSTATUS NTAPI KeWaitForSingleObject(IN PVOID Object, IN KWAIT_REASON WaitReason, IN KPROCESSOR_MODE WaitMode, IN BOOLEAN Alertable, IN PLARGE_INTEGER Timeout OPTIONAL)
Definition: wait.c:416
UCHAR TargetId
Definition: scsi_port.h:150
UCHAR SrbStatus
Definition: srb.h:243
VOID NTAPI IoFreeWorkItem(IN PIO_WORKITEM IoWorkItem)
Definition: iowork.c:64
#define SRB_STATUS(Status)
Definition: srb.h:381
VOID NTAPI IoWriteErrorLogEntry(IN PVOID ElEntry)
Definition: error.c:620
#define SENSE_BUFFER_SIZE
Definition: cdrw_hw.h:1183
struct TraceInfo Info
#define PAGED_CODE()
Definition: video.h:57
#define KdPrintEx(_x_)
Definition: kdfuncs.h:114
#define DBGTRACE(dbgTraceLevel, args_in_parens)
Definition: debug.h:136
#define IoSetCompletionRoutine(_Irp, _CompletionRoutine, _Context, _InvokeOnSuccess, _InvokeOnError, _InvokeOnCancel)
Definition: irp.cpp:515
struct _test_info info[]
Definition: SetCursorPos.c:19
#define STATUS_INVALID_DEVICE_STATE
Definition: udferr_usr.h:178
PCLASS_TICK ClassTick
Definition: classpnp.h:528
#define SP_UNTAGGED
Definition: srb.h:225
#define IRP_MJ_SCSI
#define STATUS_IO_DEVICE_ERROR
Definition: udferr_usr.h:179
#define FILE_DEVICE_CD_ROM
Definition: winioctl.h:107
NTSTATUS NTAPI ClasspInitializeGesn(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, IN PMEDIA_CHANGE_DETECTION_INFO Info)
Definition: autorun.c:1668
#define STATUS_TIMEOUT
Definition: ntstatus.h:81
_In_ PUNICODE_STRING ValueName
Definition: cmfuncs.h:264
VOID NTAPI ClassGetDeviceParameter(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, IN PWSTR SubkeyName OPTIONAL, IN PWSTR ParameterName, IN OUT PULONG ParameterValue)
Definition: utils.c:52
NTSTATUS ErrorCode
Definition: iotypes.h:1963
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 NTAPI ClassCheckMediaState(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension)
Definition: autorun.c:1404
#define NOTIFICATION_MEDIA_STATUS_CLASS_EVENTS
Definition: scsi.h:46
PRTL_QUERY_REGISTRY_ROUTINE QueryRoutine
Definition: nt_native.h:109
* PSTORAGE_DEVICE_DESCRIPTOR
Definition: ntddstor.h:457
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define SRB_CLASS_FLAGS_LOW_PRIORITY
Definition: classpnp.h:19
__inline ULONG CountOfSetBitsUChar(UCHAR _X)
Definition: tools.h:150
Definition: Header.h:8
VOID NTAPI ClasspSendNotification(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, IN const GUID *Guid, IN ULONG ExtraDataSize, IN PVOID ExtraData)
Definition: autorun.c:173
VOID NTAPI ClasspSetMediaChangeStateEx(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, IN MEDIA_CHANGE_DETECTION_STATE NewState, IN BOOLEAN Wait, IN BOOLEAN KnownStateChange)
Definition: autorun.c:716
VOID NTAPI ClasspTimerTick(PDEVICE_OBJECT DeviceObject, PVOID Context)
Definition: autorun.c:3086
long LONG
Definition: pedump.c:60
#define REG_MULTI_SZ
Definition: nt_native.h:1501
VOID NTAPI IoStopTimer(PDEVICE_OBJECT DeviceObject)
Definition: iotimer.c:166
#define FILE_REMOVABLE_MEDIA
Definition: nt_native.h:807
UCHAR ScsiStatus
Definition: srb.h:244
#define CLEAR_FLAG(Flags, Bit)
Definition: classpnp.h:155
PVOID DeviceExtension
Definition: env_spec_w32.h:418
unsigned char BOOLEAN
_In_ PCWSTR _Inout_ _At_ QueryTable EntryContext
Definition: rtlfuncs.h:3988
static GUID * Guid
Definition: apphelp.c:93
smooth NULL
Definition: ftsmooth.c:416
static __inline BOOLEAN PORT_ALLOCATED_SENSE(_In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, _In_ PSCSI_REQUEST_BLOCK Srb)
Definition: classpnp.h:1244
struct _NOTIFICATION_MEDIA_STATUS * PNOTIFICATION_MEDIA_STATUS
VOID NTAPI ClassResetMediaChangeTimer(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension)
Definition: autorun.c:1456
#define MCN_REG_AUTORUN_ENABLE_INSTANCE_NAME
Definition: autorun.c:33
union _CDB * PCDB
#define SL_OVERRIDE_VERIFY_VOLUME
Definition: iotypes.h:1779
Definition: bufpool.h:45
#define RTL_REGISTRY_OPTIONAL
Definition: nt_native.h:169
void * PVOID
Definition: retypes.h:9
UCHAR QueueTag
Definition: srb.h:248
#define MCN_REG_AUTORUN_DISABLE_INSTANCE_NAME
Definition: autorun.c:32
PIRP NTAPI ClasspPrepareMcnIrp(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, IN PMEDIA_CHANGE_DETECTION_INFO Info, IN BOOLEAN UseGesn)
Definition: autorun.c:1036
PDEVICE_OBJECT NTAPI IoGetAttachedDeviceReference(PDEVICE_OBJECT DeviceObject)
Definition: device.c:1405
#define NOTIFICATION_MEDIA_EVENT_EJECT_REQUEST
Definition: scsi.h:94
#define NOTIFICATION_MEDIA_EVENT_MEDIA_REMOVAL
Definition: scsi.h:96
PVOID NTAPI IoAllocateErrorLogEntry(IN PVOID IoObject, IN UCHAR EntrySize)
Definition: error.c:520
#define REG_OPTION_NON_VOLATILE
Definition: nt_native.h:1057
USHORT MaximumLength
Definition: env_spec_w32.h:377
int64_t LONGLONG
Definition: typedefs.h:66
#define InterlockedExchangePointer(Target, Value)
Definition: dshow.h:45
enum _CLASS_DETECTION_STATE CLASS_DETECTION_STATE
#define DBGGETSRBSTATUSSTR(_pSrb)
Definition: debug.h:145
_In_ PUCHAR EventPrefix
Definition: classpnp.h:1074
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define STATUS_PENDING
Definition: ntstatus.h:82
char CCHAR
Definition: typedefs.h:50
GLenum GLuint GLenum GLsizei length
Definition: glext.h:5579
ULONG BreakOnMcnDisable
Definition: autorun.c:2799
VOID NTAPI ClassEnableMediaChangeDetection(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension)
Definition: autorun.c:2718
NTSTATUS NTAPI IoInitializeTimer(IN PDEVICE_OBJECT DeviceObject, IN PIO_TIMER_ROUTINE TimerRoutine, IN PVOID Context)
Definition: iotimer.c:92
UCHAR Function
Definition: srb.h:242
NTSTATUS NTAPI ClassSetDeviceParameter(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, IN PWSTR SubkeyName OPTIONAL, IN PWSTR ParameterName, IN ULONG ParameterValue)
Definition: utils.c:136
static __inline VOID FREE_PORT_ALLOCATED_SENSE_BUFFER(_In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, _In_ PSCSI_REQUEST_BLOCK Srb)
Definition: classpnp.h:1255
#define IRP_MN_START_DEVICE
struct _COMMON_DEVICE_EXTENSION * PCOMMON_DEVICE_EXTENSION
_In_ GUID _In_ PVOID ValueData
Definition: hubbusif.h:311
#define SRB_FLAGS_DISABLE_SYNCH_TRANSFER
Definition: srb.h:389
#define BufferSize
Definition: classpnp.h:419
BOOLEAN NTAPI ClassInterpretSenseInfo(IN PDEVICE_OBJECT Fdo, IN PSCSI_REQUEST_BLOCK Srb, IN UCHAR MajorFunctionCode, IN ULONG IoDeviceCode, IN ULONG RetryCount, OUT NTSTATUS *Status, OUT OPTIONAL ULONG *RetryInterval)
Definition: class.c:2994
PVPB NTAPI ClassGetVpb(IN PDEVICE_OBJECT DeviceObject)
Definition: class.c:8048
VOID NTAPI ClassCleanupMediaChangeDetection(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension)
Definition: autorun.c:2849
#define SRB_FLAGS_NO_KEEP_AWAKE
Definition: srb.h:404
PDEVICE_OBJECT DeviceObject
Definition: iotypes.h:2866
NTSYSAPI VOID NTAPI RtlFreeUnicodeString(PUNICODE_STRING UnicodeString)
#define RTL_SIZEOF_THROUGH_FIELD(type, field)
Definition: ntbasedef.h:679
USHORT Length
Definition: srb.h:241
#define IRP_MJ_INTERNAL_DEVICE_CONTROL
NTSYSAPI NTSTATUS WINAPI RtlQueryRegistryValues(ULONG, PCWSTR, PRTL_QUERY_REGISTRY_TABLE, PVOID, PVOID)
* PFILE_OBJECT
Definition: iotypes.h:1954
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
struct _SCSI_REQUEST_BLOCK SCSI_REQUEST_BLOCK
struct _NOTIFICATION_EXTERNAL_STATUS * PNOTIFICATION_EXTERNAL_STATUS
VOID NTAPI IoFreeMdl(PMDL Mdl)
Definition: iomdl.c:146
PDEVICE_OBJECT DeviceObject
Definition: classpnp.h:693
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
#define CLASS_TAG_AUTORUN_DISABLE
Definition: classpnp.h:77
#define CLASSP_REG_SUBKEY_NAME
Definition: classp.h:41
#define NO_REMOVE
Definition: classpnp.h:93
unsigned char UCHAR
Definition: xmlstorage.h:181
#define SRB_FLAGS_NO_DATA_TRANSFER
Definition: srb.h:394
VOID NTAPI ClasspInternalSetMediaChangeState(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, IN MEDIA_CHANGE_DETECTION_STATE NewState, IN BOOLEAN KnownStateChange)
Definition: autorun.c:591
static double zero
Definition: j0_y0.c:96
char * PBOOLEAN
Definition: retypes.h:11
VOID NTAPI KeInitializeMutex(IN PKMUTEX Mutex, IN ULONG Level)
Definition: mutex.c:67
#define SRB_STATUS_QUEUE_FROZEN
Definition: srb.h:378
static const WCHAR L[]
Definition: oid.c:1250
#define InterlockedDecrement
Definition: armddk.h:52
#define NOTIFICATION_DEVICE_BUSY_CLASS_EVENTS
Definition: scsi.h:48
_In_ GUID _In_ PVOID _In_ ULONG ValueLength
Definition: hubbusif.h:311
PCLASS_DRIVER_EXTENSION DriverExtension
Definition: classpnp.h:576
#define RTL_REGISTRY_HANDLE
Definition: nt_native.h:168
NTSTATUS NTAPI ClassSetFailurePredictionPoll(PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, FAILURE_PREDICTION_METHOD FailurePredictionMethod, ULONG PollingPeriod)
Definition: autorun.c:3552
struct _cl_event * event
Definition: glext.h:7739
__drv_aliasesMem FORCEINLINE PIO_STACK_LOCATION IoGetNextIrpStackLocation(_In_ PIRP Irp)
Definition: iofuncs.h:2647
#define REMOVE_PENDING
Definition: classpnp.h:94
#define IOCTL_SCSI_EXECUTE_IN
Definition: cdrw_hw.h:1451
#define InterlockedExchange
Definition: armddk.h:54
#define SET_FLAG(Flags, Bit)
Definition: classpnp.h:154
#define DBGGETSENSECODESTR(_pSrb)
Definition: debug.h:141
ULONG NTAPI DebugPrint(IN PSTRING DebugString, IN ULONG ComponentId, IN ULONG Level)
Definition: debug.c:23
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
_In_ FAILURE_PREDICTION_METHOD _In_ ULONG PollingPeriod
Definition: classpnp.h:1108
#define FDO_HACK_GESN_IS_BAD
Definition: classp.h:54
VOID NTAPI ClasspInterpretGesnData(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, IN PNOTIFICATION_EVENT_STATUS_HEADER Header, IN PBOOLEAN ResendImmediately)
Definition: autorun.c:286
VOID NTAPI IoQueueWorkItem(IN PIO_WORKITEM IoWorkItem, IN PIO_WORKITEM_ROUTINE WorkerRoutine, IN WORK_QUEUE_TYPE QueueType, IN PVOID Context)
Definition: iowork.c:40
IN PDEVICE_OBJECT DeviceObject
Definition: fatprocs.h:1560
__drv_aliasesMem FORCEINLINE PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(_In_ PIRP Irp)
Definition: iofuncs.h:2745
UCHAR SenseInfoBufferLength
Definition: srb.h:251
#define IOCTL_STORAGE_PREDICT_FAILURE
Definition: ntddstor.h:135
#define WMI_STORAGE_PREDICT_FAILURE_EVENT_GUID
Definition: wmidata.h:336
#define CLASSP_REG_MMC_DETECTION_VALUE_NAME
Definition: classp.h:44
#define NOTIFICATION_EXTERNAL_REQUEST_CLASS_EVENTS
Definition: scsi.h:45
PFILE_OBJECT FileObject
Definition: iotypes.h:2812
#define CLASS_TAG_MEDIA_CHANGE_DETECTION
Definition: classpnp.h:79
VOID NTAPI ClassCompleteRequest(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN CCHAR PriorityBoost)
Definition: lock.c:376
#define KeInitializeEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:477
#define NOTIFICATION_MEDIA_EVENT_NO_CHANGE
Definition: scsi.h:93
#define InterlockedIncrement
Definition: armddk.h:53
IO_WORKITEM_ROUTINE ClasspFailurePredict
Definition: autorun.c:107
struct _FAILURE_PREDICTION_INFO * FailurePredictionInfo
Definition: classpnp.h:735
#define DPFLTR_ERROR_LEVEL
Definition: main.cpp:32
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)
#define MEDIA_CHANGE_DEFAULT_TIME
Definition: cdrom.c:176
struct _CDB::_CDB6GENERIC CDB6GENERIC
struct _NOTIFICATION_EVENT_STATUS_HEADER * PNOTIFICATION_EVENT_STATUS_HEADER
#define SRB_SIMPLE_TAG_REQUEST
Definition: srb.h:415
#define NOTIFICATION_BUSY_STATUS_NO_EVENT
Definition: scsi.h:117
unsigned int * PULONG
Definition: retypes.h:1
NTSTATUS NTAPI IoCallDriver(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
Definition: irp.c:1218
#define GESN_BUFFER_SIZE
Definition: autorun.c:29
FAILURE_PREDICTION_METHOD
Definition: classpnp.h:229
#define DEFAULT_FAILURE_PREDICTION_PERIOD
Definition: classpnp.h:186
_In_ BOOLEAN AllowDriveToSleep
Definition: classpnp.h:1082
#define STATUS_IO_TIMEOUT
Definition: udferr_usr.h:163
NTSTATUS NTAPI IoOpenDeviceRegistryKey(IN PDEVICE_OBJECT DeviceObject, IN ULONG DevInstKeyType, IN ACCESS_MASK DesiredAccess, OUT PHANDLE DevInstRegKey)
Definition: pnpmgr.c:4557
Definition: tftpd.h:85
PIRP NTAPI IoBuildDeviceIoControlRequest(IN ULONG IoControlCode, IN PDEVICE_OBJECT DeviceObject, IN PVOID InputBuffer, IN ULONG InputBufferLength, IN PVOID OutputBuffer, IN ULONG OutputBufferLength, IN BOOLEAN InternalDeviceIoControl, IN PKEVENT Event, IN PIO_STATUS_BLOCK IoStatusBlock)
Definition: irp.c:881
NTSTATUS NTAPI ClasspDisableTimer(PDEVICE_OBJECT DeviceObject)
Definition: autorun.c:3285
VOID NTAPI ClassInitializeMediaChangeDetection(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, IN PUCHAR EventPrefix)
Definition: autorun.c:2058
PVOID SenseInfoBuffer
Definition: srb.h:256
#define OUT
Definition: typedefs.h:39
VOID NTAPI IoFreeIrp(IN PIRP Irp)
Definition: irp.c:1666
#define SRB_FUNCTION_EXECUTE_SCSI
Definition: srb.h:307
CLASS_INIT_DATA InitData
Definition: classpnp.h:556
struct tagContext Context
Definition: acpixf.h:1012
#define STATUS_NOT_SUPPORTED
Definition: ntstatus.h:409
unsigned int ULONG
Definition: retypes.h:1
#define IO_NO_INCREMENT
Definition: iotypes.h:565
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
VOID NTAPI ClasspSendMediaStateIrp(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, IN PMEDIA_CHANGE_DETECTION_INFO Info, IN ULONG CountDown)
Definition: autorun.c:1215
#define SRB_STATUS_SUCCESS
Definition: srb.h:333
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
_In_ PUNICODE_STRING RegistryPath
Definition: wmip.h:27
PIRP NTAPI IoAllocateIrp(IN CCHAR StackSize, IN BOOLEAN ChargeQuota)
Definition: irp.c:615
#define DBGWARN(args_in_parens)
Definition: debug.h:134
const char * PCSTR
Definition: typedefs.h:51
NTSTATUS NTAPI ClassInitializeTestUnitPolling(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, IN BOOLEAN AllowDriveToSleep)
Definition: autorun.c:2023
struct _NOTIFICATION_BUSY_STATUS * PNOTIFICATION_BUSY_STATUS
LARGE_INTEGER SystemTime
Definition: ioevent.h:92
IN PSCSI_REQUEST_BLOCK Srb
Definition: class2.h:49
UCHAR AdditionalSenseCode
Definition: cdrw_hw.h:1175
struct _NAMED_PIPE_CREATE_PARAMETERS * Parameters
Definition: iotypes.h:2771
PCLASS_DRIVER_EXTENSION NTAPI ClassGetDriverExtension(IN PDRIVER_OBJECT DriverObject)
Definition: class.c:7236
NTSTATUS NTAPI ClasspMediaChangeDetectionCompletion(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context)
Definition: autorun.c:814
_In_ FAILURE_PREDICTION_METHOD FailurePredictionMethod
Definition: classpnp.h:1108
struct _CDB::_GET_EVENT_STATUS_NOTIFICATION GET_EVENT_STATUS_NOTIFICATION
#define DBGGETADSENSEQUALIFIERSTR(_pSrb)
Definition: debug.h:143
#define IO_WRN_FAILURE_PREDICTED
Definition: ntiologc.h:78
return STATUS_SUCCESS
Definition: btrfs.c:2725
#define RTL_QUERY_REGISTRY_REQUIRED
Definition: nt_native.h:132
NTSTATUS NTAPI IoReportTargetDeviceChangeAsynchronous(IN PDEVICE_OBJECT PhysicalDeviceObject, IN PVOID NotificationStructure, IN PDEVICE_CHANGE_COMPLETE_CALLBACK Callback OPTIONAL, IN PVOID Context OPTIONAL)
Definition: pnpreport.c:519
#define REG_DWORD
Definition: sdbapi.c:596
signed int * PLONG
Definition: retypes.h:5
BOOLEAN NTAPI ClasspIsMediaChangeDisabledForClass(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, IN PUNICODE_STRING RegistryPath)
Definition: autorun.c:2569
#define VPB_MOUNTED
Definition: iotypes.h:1763
static SERVICE_STATUS status
Definition: service.c:31
#define OBJ_KERNEL_HANDLE
Definition: winternl.h:231
#define MCN_REG_SUBKEY_NAME
Definition: autorun.c:31
FORCEINLINE VOID IoSetNextIrpStackLocation(_Inout_ PIRP Irp)
Definition: iofuncs.h:2632
struct CFHEADER header
Definition: fdi.c:109
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
#define RTL_QUERY_REGISTRY_DIRECT
Definition: nt_native.h:144
#define RtlCompareMemory(s1, s2, l)
Definition: env_spec_w32.h:465
#define ClasspCanSendPollingIrp(fdoExtension)
Definition: autorun.c:54
LONGLONG QuadPart
Definition: typedefs.h:112
NTSTATUS NTAPI ClassWmiFireEvent(IN PDEVICE_OBJECT DeviceObject, IN LPGUID Guid, IN ULONG InstanceIndex, IN ULONG EventDataSize, IN PVOID EventData)
Definition: classwmi.c:721
VOID NTAPI ClassReleaseRemoveLock(IN PDEVICE_OBJECT DeviceObject, IN OPTIONAL PIRP Tag)
Definition: lock.c:212
#define IRP_MJ_DEVICE_CONTROL
Definition: rdpdr.c:52
IN BOOLEAN Wait
Definition: fatprocs.h:1529
NTSTATUS NTAPI ClasspMediaChangeRegistryCallBack(IN PWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData, IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext)
Definition: autorun.c:2998
#define REG_SZ
Definition: layer.c:22
Definition: ps.c:97