ReactOS 0.4.15-dev-7711-g5627da4
autorun.c
Go to the documentation of this file.
1/*++
2
3Copyright (C) Microsoft Corporation, 1991 - 2010
4
5Module Name:
6
7 autorun.c
8
9Abstract:
10
11 Code for support of media change detection in the class driver
12
13Environment:
14
15 kernel mode only
16
17Notes:
18
19
20Revision History:
21
22--*/
23
24#include "classp.h"
25#include "debug.h"
26
27#ifdef DEBUG_USE_WPP
28#include "autorun.tmh"
29#endif
30
31#define GESN_TIMEOUT_VALUE (0x4)
32#define GESN_BUFFER_SIZE (0x8)
33#define GESN_DEVICE_BUSY_LOWER_THRESHOLD_100_MS (2)
34
35#define MAXIMUM_IMMEDIATE_MCN_RETRIES (0x20)
36#define MCN_REG_SUBKEY_NAME (L"MediaChangeNotification")
37#define MCN_REG_AUTORUN_DISABLE_INSTANCE_NAME (L"AlwaysDisableMCN")
38#define MCN_REG_AUTORUN_ENABLE_INSTANCE_NAME (L"AlwaysEnableMCN")
39
41
42//
43// Only send polling irp when device is fully powered up, a
44// power down irp is not in progress, and the screen is on.
45//
46// NOTE: This helps close a window in time where a polling irp could cause
47// a drive to spin up right after it has powered down. The problem is
48// that SCSIPORT, ATAPI and SBP2 will be in the process of powering
49// down (which may take a few seconds), but won't know that. It would
50// then get a polling irp which will be put into its queue since it
51// the disk isn't powered down yet. Once the disk is powered down it
52// will find the polling irp in the queue and then power up the
53// device to do the poll. They do not want to check if the polling
54// irp has the SRB_NO_KEEP_AWAKE flag here since it is in a critical
55// path and would slow down all I/Os. A better way to fix this
56// would be to serialize the polling and power down irps so that
57// only one of them is sent to the device at a time.
58//
59static
63 )
64{
65 return ((fdoExtension->DevicePowerState == PowerDeviceD0) &&
66 (fdoExtension->PowerDownInProgress == FALSE) &&
68}
69
74 );
75
80 );
81
86 );
87
88VOID
93 IN BOOLEAN KnownStateChange // can ignore oldstate == unknown
94 );
95
96RTL_QUERY_REGISTRY_ROUTINE ClasspMediaChangeRegistryCallBack;
97
98VOID
102 IN ULONG CountDown
103 );
104
105IO_WORKITEM_ROUTINE ClasspFailurePredict;
106
111 );
112
113
114IO_WORKITEM_ROUTINE ClasspDisableGesn;
115
117
118KDEFERRED_ROUTINE ClasspTimerTick;
119
120#if (NTDDI_VERSION >= NTDDI_WINBLUE)
121EXT_CALLBACK ClasspTimerTickEx;
122#endif
123
125
126//
127// Tick timer related defines.
128//
129#define TICK_TIMER_PERIOD_IN_MSEC 1000
130#define TICK_TIMER_DELAY_IN_MSEC 1000
131
132#if ALLOC_PRAGMA
133
134#pragma alloc_text(PAGE, ClassInitializeMediaChangeDetection)
135#pragma alloc_text(PAGE, ClassEnableMediaChangeDetection)
136#pragma alloc_text(PAGE, ClassDisableMediaChangeDetection)
137#pragma alloc_text(PAGE, ClassCleanupMediaChangeDetection)
138#pragma alloc_text(PAGE, ClasspMediaChangeRegistryCallBack)
139#pragma alloc_text(PAGE, ClasspInitializePolling)
140#pragma alloc_text(PAGE, ClasspDisableGesn)
141
142#pragma alloc_text(PAGE, ClasspIsMediaChangeDisabledDueToHardwareLimitation)
143#pragma alloc_text(PAGE, ClasspMediaChangeDeviceInstanceOverride)
144#pragma alloc_text(PAGE, ClasspIsMediaChangeDisabledForClass)
145
146#pragma alloc_text(PAGE, ClassSetFailurePredictionPoll)
147
148#pragma alloc_text(PAGE, ClasspInitializeGesn)
149#pragma alloc_text(PAGE, ClasspMcnControl)
150
151#endif
152
153// ISSUE -- make this public?
154VOID
157 )
158{
159 //
160 // For post-NT5.1 work, need to move EjectSynchronizationEvent
161 // to be a MUTEX so we can attempt to grab it here and benefit
162 // from deadlock detection. This will allow checking if the media
163 // has been locked by programs before broadcasting these events.
164 // (what's the point of broadcasting if the media is not locked?)
165 //
166 // This would currently only be a slight optimization. For post-NT5.1,
167 // it would allow us to send a single PERSISTENT_PREVENT to MMC devices,
168 // thereby cleaning up a lot of the ejection code. Then, when the
169 // ejection request occured, we could see if any locks for the media
170 // existed. if locked, broadcast. if not, we send the eject irp.
171 //
172
173 //
174 // for now, just always broadcast. make this a public routine,
175 // so class drivers can add special hacks to broadcast this for their
176 // non-MMC-compliant devices also from sense codes.
177 //
178
179 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "ClassSendEjectionNotification: media EJECT_REQUEST"));
180 ClassSendNotification(FdoExtension,
181 &GUID_IO_MEDIA_EJECT_REQUEST,
182 0,
183 NULL);
184 return;
185}
186
187
189VOID
190NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
191ClassSendNotification(
193 _In_ const GUID * Guid,
196 )
197{
199 ULONG requiredSize;
201
202 status = RtlULongAdd((sizeof(TARGET_DEVICE_CUSTOM_NOTIFICATION) - sizeof(UCHAR)),
204 &requiredSize);
205
206 if (!(NT_SUCCESS(status)) || (requiredSize > 0x0000ffff)) {
207 // MAX_USHORT, max total size for these events!
208 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN,
209 "Error sending event: size too large! (%x)\n",
210 requiredSize));
211 return;
212 }
213
214 notification = ExAllocatePoolWithTag(NonPagedPoolNx,
215 requiredSize,
216 'oNcS');
217
218 //
219 // if none allocated, exit
220 //
221
222 if (notification == NULL) {
223 return;
224 }
225
226 //
227 // Prepare and send the request!
228 //
229
230 RtlZeroMemory(notification, requiredSize);
231 notification->Version = 1;
232 notification->Size = (USHORT)(requiredSize);
233 notification->FileObject = NULL;
234 notification->NameBufferOffset = -1;
235 notification->Event = *Guid;
236
237 if (ExtraData != NULL && ExtraDataSize != 0) {
238 RtlCopyMemory(notification->CustomDataBuffer, ExtraData, ExtraDataSize);
239 }
240
243 NULL, NULL);
244
246 return;
247}
248
249
254 OUT PBOOLEAN ResendImmediately
255 )
256
257/*++
258
259Routine Description:
260
261 This routine will interpret the data returned for a GESN command, and
262 (if appropriate) set the media change event, and broadcast the
263 appropriate events to user mode for applications who care.
264
265Arguments:
266
267 FdoExtension - the device
268
269 DataBuffer - the resulting data from a GESN event.
270 requires at least EIGHT valid bytes (header == 4, data == 4)
271
272 ResendImmediately - whether or not to immediately resend the request.
273 this should be FALSE if there was no event, FALSE if the reported
274 event was of the DEVICE BUSY class, else true.
275
276Return Value:
277
278 STATUS_SUCCESS if successful, an error code otherwise
279
280Notes:
281
282 DataBuffer must be at least four bytes of valid data (header == 4 bytes),
283 and have at least eight bytes of allocated memory (all events == 4 bytes).
284
285 The call to StartNextPacket may occur before this routine is completed.
286 the operational change notifications are informational in nature, and
287 while useful, are not neccessary to ensure proper operation. For example,
288 if the device morphs to no longer supporting WRITE commands, all further
289 write commands will fail. There exists a small timing window wherein
290 IOCTL_IS_DISK_WRITABLE may be called and get an incorrect response. If
291 a device supports software write protect, it is expected that the
292 application can handle such a case.
293
294 NOTE: perhaps setting the updaterequired byte to one should be done here.
295 if so, it relies upon the setting of a 32-byte value to be an atomic
296 operation. unfortunately, there is no simple way to notify a class driver
297 which wants to know that the device behavior requires updating.
298
299 Not ready events may be sent every second. For example, if we were
300 to minimize the number of asynchronous notifications, an application may
301 register just after a large busy time was reported. This would then
302 prevent the application from knowing the device was busy until some
303 arbitrarily chosen timeout has occurred. Also, the GESN request would
304 have to still occur, since it checks for non-busy events (such as user
305 keybutton presses and media change events) as well. The specification
306 states that the lower-numered events get reported first, so busy events,
307 while repeating, will only be reported when all other events have been
308 cleared from the device.
309
310--*/
311
312{
315 LONG requiredLength;
317
318 info = FdoExtension->MediaChangeDetectionInfo;
319
320 //
321 // note: don't allocate anything in this routine so that we can
322 // always just 'return'.
323 //
324
325 *ResendImmediately = FALSE;
326 if (Header->NEA) {
327 return status;
328 }
329 if (Header->NotificationClass == NOTIFICATION_NO_CLASS_EVENTS) {
330 return status;
331 }
332
333 //
334 // HACKHACK - REF #0001
335 // This loop is only taken initially, due to the inability to reliably
336 // auto-detect drives that report events correctly at boot. When we
337 // detect this behavior during the normal course of running, we will
338 // disable the hack, allowing more efficient use of the system. This
339 // should occur "nearly" instantly, as the drive should have multiple
340 // events queue'd (ie. power, morphing, media).
341 //
342
343 if (info->Gesn.HackEventMask) {
344
345 //
346 // all events use the low four bytes of zero to indicate
347 // that there was no change in status.
348 //
349
350 UCHAR thisEvent = Header->ClassEventData[0] & 0xf;
351 UCHAR lowestSetBit;
352 UCHAR thisEventBit = (1 << Header->NotificationClass);
353
354 if (!TEST_FLAG(info->Gesn.EventMask, thisEventBit)) {
355
356 //
357 // The drive is reporting an event that wasn't requested
358 //
359
361 }
362
363 //
364 // some bit magic here... this results in the lowest set bit only
365 //
366
367 lowestSetBit = info->Gesn.EventMask;
368 lowestSetBit &= (info->Gesn.EventMask - 1);
369 lowestSetBit ^= (info->Gesn.EventMask);
370
371 if (thisEventBit != lowestSetBit) {
372
373 //
374 // HACKHACK - REF #0001
375 // the first time we ever see an event set that is not the lowest
376 // set bit in the request (iow, highest priority), we know that the
377 // hack is no longer required, as the device is ignoring "no change"
378 // events when a real event is waiting in the other requested queues.
379 //
380
381 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
382 "Classpnp => GESN::NONE: Compliant drive found, "
383 "removing GESN hack (%x, %x)\n",
384 thisEventBit, info->Gesn.EventMask));
385
386 info->Gesn.HackEventMask = FALSE;
387
388 } else if (thisEvent == 0) { // NOTIFICATION_*_EVENT_NO_CHANGE
389
390 //
391 // HACKHACK - REF #0001
392 // note: this hack prevents poorly implemented firmware from constantly
393 // returning "No Event". we do this by cycling through the
394 // supported list of events here.
395 //
396
397 SET_FLAG(info->Gesn.NoChangeEventMask, thisEventBit);
398 CLEAR_FLAG(info->Gesn.EventMask, thisEventBit);
399
400 //
401 // if we have cycled through all supported event types, then
402 // we need to reset the events we are asking about. else we
403 // want to resend this request immediately in case there was
404 // another event pending.
405 //
406
407 if (info->Gesn.EventMask == 0) {
408 info->Gesn.EventMask = info->Gesn.NoChangeEventMask;
409 info->Gesn.NoChangeEventMask = 0;
410 } else {
411 *ResendImmediately = TRUE;
412 }
413 return status;
414 }
415
416 } // end if (info->Gesn.HackEventMask)
417
418 dataLength =
419 (Header->EventDataLength[0] << 8) |
420 (Header->EventDataLength[1] & 0xff);
421 dataLength -= 2;
422 requiredLength = 4; // all events are four bytes
423
424 if (dataLength < requiredLength) {
425 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN,
426 "Classpnp => GESN returned only %x bytes data for fdo %p\n",
427 dataLength, FdoExtension->DeviceObject));
428
430 }
431 if (dataLength != requiredLength) {
432 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN,
433 "Classpnp => GESN returned too many (%x) bytes data for fdo %p\n",
434 dataLength, FdoExtension->DeviceObject));
435 // dataLength = 4;
436 }
437
438 NT_ASSERT(dataLength == 4);
439
440 if ((Header->ClassEventData[0] & 0xf) == 0)
441 {
442 // a zero event is a "no change event, so do not retry
443 return status;
444 }
445
446 // because a event other than "no change" occurred,
447 // we should immediately resend this request.
448 *ResendImmediately = TRUE;
449
450
451/*
452 ClassSendNotification(FdoExtension,
453 &GUID_IO_GENERIC_GESN_EVENT,
454 sizeof(NOTIFICATION_EVENT_STATUS_HEADER) + dataLength,
455 Header)
456*/
457
458
459
460 switch (Header->NotificationClass) {
461
463
465 (PNOTIFICATION_OPERATIONAL_STATUS)(Header->ClassEventData);
466 ULONG event;
467
469 break;
470 }
471
472 event = (opChangeInfo->Operation[0] << 8) |
473 (opChangeInfo->Operation[1] ) ;
474
475 // Workaround some hardware that is buggy but prevalent in the market
476 // This hardware has the property that it will report OpChange events repeatedly,
477 // causing us to retry immediately so quickly that we will eventually disable
478 // GESN to prevent an infinite loop.
479 // (only one valid OpChange event type now, only two ever defined)
480 if (info->MediaChangeRetryCount >= 4) {
481
482 //
483 // HACKHACK - REF #0002
484 // Some drives incorrectly report OpChange/Change (001b/0001h) events
485 // continuously when the tray has been ejected. This causes this routine
486 // to set ResendImmediately to "TRUE", and that results in our cycling
487 // 32 times immediately resending. At that point, we give up detecting
488 // the infinite retry loop, and disable GESN on these drives. This
489 // prevents Media Eject Request (from eject button) from being reported.
490 // Thus, instead we should attempt to workaround this issue by detecting
491 // this behavior.
492 //
493
494 static UCHAR const OpChangeMask = 0x02;
495
496 // At least one device reports "temporarily busy" (which is useless) on eject
497 // At least one device reports "OpChange" repeatedly when re-inserting media
498 // All seem to work well using this workaround
499
500 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_MCN,
501 "Classpnp => GESN OpChange events are broken. Working around this "
502 "problem in software (for fdo %p)\n",
503 FdoExtension->DeviceObject));
504
505
506 // OpChange is not the only bit set -- Media class is required....
507 NT_ASSERT(CountOfSetBitsUChar(info->Gesn.EventMask) != 1);
508
509 //
510 // Force the use of the hackhack (ref #0001) to workaround the
511 // issue noted this hackhack (ref #0002).
512 //
513 SET_FLAG(info->Gesn.NoChangeEventMask, OpChangeMask);
514 CLEAR_FLAG(info->Gesn.EventMask, OpChangeMask);
515 info->Gesn.HackEventMask = TRUE;
516
517 //
518 // don't request the opChange event again. use the method
519 // defined by hackhack (ref #0001) as the workaround.
520 //
521
522 if (info->Gesn.EventMask == 0) {
523 info->Gesn.EventMask = info->Gesn.NoChangeEventMask;
524 info->Gesn.NoChangeEventMask = 0;
525 *ResendImmediately = FALSE;
526 } else {
527 *ResendImmediately = TRUE;
528 }
529
530 break;
531 }
532
533
536
537 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
538 "Classpnp => GESN says features added/changedfor fdo %p\n",
539 FdoExtension->DeviceObject));
540
541 // don't notify that new media arrived, just set the
542 // DO_VERIFY to force a FS reload.
543
544 if (TEST_FLAG(FdoExtension->DeviceObject->Characteristics,
546 (ClassGetVpb(FdoExtension->DeviceObject) != NULL) &&
547 (ClassGetVpb(FdoExtension->DeviceObject)->Flags & VPB_MOUNTED)
548 ) {
549
550 SET_FLAG(FdoExtension->DeviceObject->Flags, DO_VERIFY_VOLUME);
551 }
552
553 //
554 // If there is a class specific error handler, call it with
555 // a "fake" media change error in case it needs to update
556 // internal structures as though a media change occurred.
557 //
558
559 if (FdoExtension->CommonExtension.DevInfo->ClassError != NULL) {
560
561 SCSI_REQUEST_BLOCK srb = {0};
562 UCHAR srbExBuffer[CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE] = {0};
564 PSCSI_REQUEST_BLOCK srbPtr;
565
566 SENSE_DATA sense = {0};
567 NTSTATUS tempStatus;
568 BOOLEAN retry;
569
570 tempStatus = STATUS_MEDIA_CHANGED;
571 retry = FALSE;
572
574
575 sense.AdditionalSenseLength = sizeof(SENSE_DATA) -
576 RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseLength);
577
580
581 //
582 // Send the right type of SRB to the class driver
583 //
584 if ((FdoExtension->CommonExtension.DriverExtension->SrbSupport &
586#ifdef _MSC_VER
587 #pragma prefast(suppress:26015, "InitializeStorageRequestBlock ensures buffer access is bounded")
588#endif
592 1,
594 if (NT_SUCCESS(status)) {
595 SrbSetCdbLength(srbEx, 6);
596 srbEx->SrbStatus = SRB_STATUS_AUTOSENSE_VALID | SRB_STATUS_ERROR;
597 SrbSetSenseInfoBuffer(srbEx, &sense);
598 SrbSetSenseInfoBufferLength(srbEx, sizeof(sense));
599 srbPtr = (PSCSI_REQUEST_BLOCK)srbEx;
600 } else {
601 // should not happen. Revert to legacy SRB.
603 srb.CdbLength = 6;
604 srb.Length = sizeof(SCSI_REQUEST_BLOCK);
606 srb.SenseInfoBuffer = &sense;
607 srb.SenseInfoBufferLength = sizeof(SENSE_DATA);
608 srbPtr = &srb;
609 }
610 } else {
611 srb.CdbLength = 6;
612 srb.Length = sizeof(SCSI_REQUEST_BLOCK);
614 srb.SenseInfoBuffer = &sense;
615 srb.SenseInfoBufferLength = sizeof(SENSE_DATA);
616 srbPtr = &srb;
617 }
618
619 FdoExtension->CommonExtension.DevInfo->ClassError(FdoExtension->DeviceObject,
620 srbPtr,
621 &tempStatus,
622 &retry);
623
624 } // end class error handler
625
626 }
627 break;
628 }
629
631
632 PNOTIFICATION_EXTERNAL_STATUS externalInfo =
633 (PNOTIFICATION_EXTERNAL_STATUS)(Header->ClassEventData);
634 DEVICE_EVENT_EXTERNAL_REQUEST externalData = {0};
635
636 //
637 // unfortunately, due to time constraints, we will only notify
638 // about keys being pressed, and not released. this makes keys
639 // single-function, but simplifies the code significantly.
640 //
641
643 break;
644 }
645
646 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
647 "Classpnp => GESN::EXTERNAL: Event: %x Status %x Req %x\n",
648 externalInfo->ExternalEvent, externalInfo->ExternalStatus,
649 (externalInfo->Request[0] << 8) | externalInfo->Request[1]
650 ));
651
652 externalData.Version = 1;
653 externalData.DeviceClass = 0;
654 externalData.ButtonStatus = externalInfo->ExternalEvent;
655 externalData.Request =
656 (externalInfo->Request[0] << 8) |
657 (externalInfo->Request[1] & 0xff);
658 KeQuerySystemTime(&(externalData.SystemTime));
660
661 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "ClasspInterpretGesnData: media DEVICE_EXTERNAL_REQUEST"));
662 ClassSendNotification(FdoExtension,
663 &GUID_IO_DEVICE_EXTERNAL_REQUEST,
665 &externalData);
666 return status;
667 }
668
670
672 (PNOTIFICATION_MEDIA_STATUS)(Header->ClassEventData);
673
674 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
675 "Classpnp => GESN::MEDIA: Event: %x Status %x\n",
676 mediaInfo->MediaEvent, mediaInfo->MediaStatus));
677
680
681
682 if (TEST_FLAG(FdoExtension->DeviceObject->Characteristics,
684 (ClassGetVpb(FdoExtension->DeviceObject) != NULL) &&
685 (ClassGetVpb(FdoExtension->DeviceObject)->Flags & VPB_MOUNTED)
686 ) {
687
688 SET_FLAG(FdoExtension->DeviceObject->Flags, DO_VERIFY_VOLUME);
689
690 }
691 InterlockedIncrement((volatile LONG *)&FdoExtension->MediaChangeCount);
694 FALSE,
695 TRUE);
696
697 } else if (mediaInfo->MediaEvent == NOTIFICATION_MEDIA_EVENT_MEDIA_REMOVAL) {
698
701 FALSE,
702 TRUE);
703
704 } else if (mediaInfo->MediaEvent == NOTIFICATION_MEDIA_EVENT_EJECT_REQUEST) {
705
706 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
707 "Classpnp => GESN Ejection request received!\n"));
709
710 }
711 break;
712
713 }
714
715 case NOTIFICATION_DEVICE_BUSY_CLASS_EVENTS: { // lowest priority events...
716
718 (PNOTIFICATION_BUSY_STATUS)(Header->ClassEventData);
719 DEVICE_EVENT_BECOMING_READY busyData = {0};
720
721 //
722 // NOTE: we never actually need to immediately retry for these
723 // events: if one exists, the device is busy, and if not,
724 // we still don't want to retry.
725 //
726
727 *ResendImmediately = FALSE;
728
729 //
730 // else we want to report the approximated time till it's ready.
731 //
732
733 busyData.Version = 1;
734 busyData.Reason = busyInfo->DeviceBusyStatus;
735 busyData.Estimated100msToReady = (busyInfo->Time[0] << 8) |
736 (busyInfo->Time[1] & 0xff);
737
738 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
739 "Classpnp => GESN::BUSY: Event: %x Status %x Time %x\n",
740 busyInfo->DeviceBusyEvent, busyInfo->DeviceBusyStatus,
741 busyData.Estimated100msToReady
742 ));
743
744 //
745 // Ignore the notification if the time is small
746 //
748 break;
749 }
750
751
752 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "ClasspInterpretGesnData: media BECOMING_READY"));
753 ClassSendNotification(FdoExtension,
754 &GUID_IO_DEVICE_BECOMING_READY,
756 &busyData);
757 break;
758 }
759
760 default: {
761
762 break;
763
764 }
765
766 } // end switch on notification class
767 return status;
768}
769
770/*++////////////////////////////////////////////////////////////////////////////
771
772ClasspInternalSetMediaChangeState()
773
774Routine Description:
775
776 This routine will (if appropriate) set the media change event for the
777 device. The event will be set if the media state is changed and
778 media change events are enabled. Otherwise the media state will be
779 tracked but the event will not be set.
780
781 This routine will lock out the other media change routines if possible
782 but if not a media change notification may be lost after the enable has
783 been completed.
784
785Arguments:
786
787 FdoExtension - the device
788
789 MediaPresent - indicates whether the device has media inserted into it
790 (TRUE) or not (FALSE).
791
792Return Value:
793
794 none
795
796--*/
797VOID
801 IN BOOLEAN KnownStateChange // can ignore oldstate == unknown
802 )
803{
804#if DBG
805 PCSZ states[] = {"Unknown", "Present", "Not Present", "Unavailable"};
806#endif
807 MEDIA_CHANGE_DETECTION_STATE oldMediaState;
808 PMEDIA_CHANGE_DETECTION_INFO info = FdoExtension->MediaChangeDetectionInfo;
810 PIO_WORKITEM workItem;
811
812 if (!((NewState >= MediaUnknown) && (NewState <= MediaUnavailable))) {
813 return;
814 }
815
816 if(info == NULL) {
817 return;
818 }
819
820 oldMediaState = InterlockedExchange(
821 (PLONG)(&info->MediaChangeDetectionState),
822 (LONG)NewState);
823
824 if((oldMediaState == MediaUnknown) && (!KnownStateChange)) {
825
826 //
827 // The media was in an indeterminate state before - don't notify for
828 // this change.
829 //
830
831 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
832 "ClassSetMediaChangeState: State was unknown - this may "
833 "not be a change\n"));
834 return;
835
836 } else if(oldMediaState == NewState) {
837
838 //
839 // Media is in the same state it was before.
840 //
841
842 return;
843 }
844
845 //
846 // Inform PartMgr that the media changed. It will need to propagate
847 // DO_VERIFY_VOLUME to each partition. Ensure that only one work item
848 // updates the disk's properties at any given time.
849 //
850 if (InterlockedCompareExchange((volatile LONG *)&FdoExtension->PrivateFdoData->UpdateDiskPropertiesWorkItemActive, 1, 0) == 0) {
851
852 workItem = IoAllocateWorkItem(FdoExtension->DeviceObject);
853
854 if (workItem) {
855
857
858 } else {
859
860 InterlockedExchange((volatile LONG *)&FdoExtension->PrivateFdoData->UpdateDiskPropertiesWorkItemActive, 0);
861 }
862 }
863
864 if(info->MediaChangeDetectionDisableCount != 0) {
865#if DBG
866 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
867 "ClassSetMediaChangeState: MCN not enabled, state "
868 "changed from %s to %s\n",
869 states[oldMediaState], states[NewState]));
870#endif
871 return;
872
873 }
874#if DBG
875 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
876 "ClassSetMediaChangeState: State change from %s to %s\n",
877 states[oldMediaState], states[NewState]));
878#endif
879
880 //
881 // make the data useful -- it used to always be zero.
882 //
883 mcnContext.MediaChangeCount = FdoExtension->MediaChangeCount;
884 mcnContext.NewState = NewState;
885
886 if (NewState == MediaPresent) {
887
888 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "ClasspInternalSetMediaChangeState: media ARRIVAL"));
889 ClassSendNotification(FdoExtension,
890 &GUID_IO_MEDIA_ARRIVAL,
892 &mcnContext);
893
894 }
895 else if ((NewState == MediaNotPresent) || (NewState == MediaUnavailable)) {
896
897 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "ClasspInternalSetMediaChangeState: media REMOVAL"));
898 ClassSendNotification(FdoExtension,
899 &GUID_IO_MEDIA_REMOVAL,
901 &mcnContext);
902
903 } else {
904
905 //
906 // Don't notify of changed going to unknown.
907 //
908
909 return;
910 }
911
912 return;
913} // end ClasspInternalSetMediaChangeState()
914
915/*++////////////////////////////////////////////////////////////////////////////
916
917ClassSetMediaChangeState()
918
919Routine Description:
920
921 This routine will (if appropriate) set the media change event for the
922 device. The event will be set if the media state is changed and
923 media change events are enabled. Otherwise the media state will be
924 tracked but the event will not be set.
925
926 This routine will lock out the other media change routines if possible
927 but if not a media change notification may be lost after the enable has
928 been completed.
929
930Arguments:
931
932 FdoExtension - the device
933
934 MediaPresent - indicates whether the device has media inserted into it
935 (TRUE) or not (FALSE).
936
937 Wait - indicates whether the function should wait until it can acquire
938 the synchronization lock or not.
939
940Return Value:
941
942 none
943
944--*/
945
946VOID
947#ifdef _MSC_VER
948#pragma prefast(suppress:26165, "The mutex won't be acquired in the case of a timeout.")
949#endif
954 IN BOOLEAN KnownStateChange // can ignore oldstate == unknown
955 )
956{
957 PMEDIA_CHANGE_DETECTION_INFO info = FdoExtension->MediaChangeDetectionInfo;
960
961 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "> ClasspSetMediaChangeStateEx"));
962
963 //
964 // Reset SMART status on media removal as the old status may not be
965 // valid when there is no media in the device or when new media is
966 // inserted.
967 //
968
969 if (NewState == MediaNotPresent) {
970
971 FdoExtension->FailurePredicted = FALSE;
972 FdoExtension->FailureReason = 0;
973
974 }
975
976
977 zero.QuadPart = 0;
978
979 if(info == NULL) {
980 return;
981 }
982
983 status = KeWaitForMutexObject(&info->MediaChangeMutex,
984 Executive,
986 FALSE,
987 ((Wait == TRUE) ? NULL : &zero));
988
989 if(status == STATUS_TIMEOUT) {
990
991 //
992 // Someone else is in the process of setting the media state
993 //
994
995 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN, "ClasspSetMediaChangeStateEx - timed out waiting for mutex"));
996 return;
997 }
998
999 //
1000 // Change the media present state and signal an event, if applicable
1001 //
1002
1003 ClasspInternalSetMediaChangeState(FdoExtension, NewState, KnownStateChange);
1004
1005 KeReleaseMutex(&info->MediaChangeMutex, FALSE);
1006
1007 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "< ClasspSetMediaChangeStateEx"));
1008
1009 return;
1010} // end ClassSetMediaChangeStateEx()
1011
1013VOID
1014NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
1015ClassSetMediaChangeState(
1019 )
1020{
1022 return;
1023}
1024
1025/*++////////////////////////////////////////////////////////////////////////////
1026
1027ClasspMediaChangeDetectionCompletion()
1028
1029Routine Description:
1030
1031 This routine handles the completion of the test unit ready irps used to
1032 determine if the media has changed. If the media has changed, this code
1033 signals the named event to wake up other system services that react to
1034 media change (aka AutoPlay).
1035
1036Arguments:
1037
1038 DeviceObject - the object for the completion
1039 Irp - the IRP being completed
1040 Context - the SRB from the IRP
1041
1042Return Value:
1043
1044 NTSTATUS
1045
1046--*/
1048NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
1051 PIRP Irp,
1053 )
1054{
1055 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
1059 BOOLEAN retryImmediately = FALSE;
1061
1063
1064 //
1065 // Since the class driver created this request, it's completion routine
1066 // will not get a valid device object handed in. Use the one in the
1067 // irp stack instead
1068 //
1069
1071 fdoExtension = DeviceObject->DeviceExtension;
1072 fdoData = fdoExtension->PrivateFdoData;
1073 info = fdoExtension->MediaChangeDetectionInfo;
1074
1075 NT_ASSERT(info->MediaChangeIrp != NULL);
1077 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_MCN, "> ClasspMediaChangeDetectionCompletion: Device %p completed MCN irp %p.", DeviceObject, Irp));
1078
1079 /*
1080 * HACK for IoMega 2GB Jaz drive:
1081 * This drive spins down on its own to preserve the media.
1082 * When spun down, TUR fails with 2/4/0 (SCSI_SENSE_NOT_READY/SCSI_ADSENSE_LUN_NOT_READY/?).
1083 * InterpretSenseInfo routine would then call ClassSendStartUnit to spin the media up, which defeats the
1084 * purpose of the spindown.
1085 * So in this case, make this into a successful TUR.
1086 * This allows the drive to stay spun down until it is actually accessed again.
1087 * (If the media were actually removed, TUR would fail with 2/3a/0 ).
1088 * This hack only applies to drives with the CAUSE_NOT_REPORTABLE_HACK bit set; this
1089 * is set by disk.sys when HackCauseNotReportableHack is set for the drive in its BadControllers list.
1090 */
1091
1094
1095 PVOID senseData = SrbGetSenseInfoBuffer(Srb);
1096
1097 if (senseData) {
1098
1100 UCHAR senseInfoBufferLength = SrbGetSenseInfoBufferLength(Srb);
1101 UCHAR senseKey = 0;
1103
1104 validSense = ScsiGetSenseKeyAndCodes(senseData,
1105 senseInfoBufferLength,
1107 &senseKey,
1109 NULL);
1110
1111 if (validSense &&
1115 }
1116 }
1117 }
1118
1119 //
1120 // use InterpretSenseInfo routine to check for media state, and also
1121 // to call ClassError() with correct parameters.
1122 //
1125
1126 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN, "ClasspMediaChangeDetectionCompletion - failed - srb status=%s, sense=%s/%s/%s.",
1128
1130 Irp,
1133 0,
1134 0,
1135 &status,
1136 NULL);
1137 }
1138 else {
1139
1141
1142 if (!info->Gesn.Supported) {
1143
1144 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "ClasspMediaChangeDetectionCompletion - succeeded and GESN NOT supported, setting MediaPresent."));
1145
1146 //
1147 // success != media for GESN case
1148 //
1149
1150 ClassSetMediaChangeState(fdoExtension, MediaPresent, FALSE);
1151
1152 }
1153 else {
1154 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "ClasspMediaChangeDetectionCompletion - succeeded (GESN supported)."));
1155 }
1156 }
1157
1158 if (info->Gesn.Supported) {
1159
1160 if (status == STATUS_DATA_OVERRUN) {
1161 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "ClasspMediaChangeDetectionCompletion - Overrun"));
1163 }
1164
1165 if (!NT_SUCCESS(status)) {
1166 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "ClasspMediaChangeDetectionCompletion: GESN failed with status %x", status));
1167 } else {
1168
1169 //
1170 // for GESN, need to interpret the results of the data.
1171 // this may also require an immediate retry
1172 //
1173
1174 if (Irp->IoStatus.Information == 8 ) {
1175 ClasspInterpretGesnData(fdoExtension,
1176 (PVOID)info->Gesn.Buffer,
1177 &retryImmediately);
1178 }
1179
1180 } // end of NT_SUCCESS(status)
1181
1182 } // end of Info->Gesn.Supported
1183
1184 //
1185 // free port-allocated sense buffer, if any.
1186 //
1187
1188 if (PORT_ALLOCATED_SENSE_EX(fdoExtension, Srb)) {
1190 }
1191
1192 //
1193 // Remember the IRP and SRB for use the next time.
1194 //
1195
1198
1199 //
1200 // Reset the MCN timer.
1201 //
1202
1203 ClassResetMediaChangeTimer(fdoExtension);
1204
1205 //
1206 // run a sanity check to make sure we're not recursing continuously
1207 //
1208
1209 if (retryImmediately) {
1210
1211 info->MediaChangeRetryCount++;
1212
1213 if (info->MediaChangeRetryCount > MAXIMUM_IMMEDIATE_MCN_RETRIES) {
1214
1215 //
1216 // Disable GESN on this device.
1217 // Create a work item to set the value in the registry
1218 //
1219
1220 PIO_WORKITEM workItem;
1221
1222 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "ClasspMediaChangeDetectionCompletion: Disabling GESN for device %p", DeviceObject));
1223
1224 workItem = IoAllocateWorkItem(DeviceObject);
1225
1226 if (workItem) {
1228 }
1229
1230 info->Gesn.Supported = 0;
1231 info->Gesn.EventMask = 0;
1232 info->Gesn.BufferSize = 0;
1233 info->MediaChangeRetryCount = 0;
1234 retryImmediately = FALSE;
1235 }
1236
1237 } else {
1238
1239 info->MediaChangeRetryCount = 0;
1240
1241 }
1242
1243
1244 //
1245 // release the remove lock....
1246 //
1247
1248 {
1249 UCHAR uniqueValue = 0;
1250 ClassAcquireRemoveLock(DeviceObject, (PVOID)(&uniqueValue));
1252
1253
1254 //
1255 // set the irp as not in use
1256 //
1257 {
1258#if DBG
1259 volatile LONG irpWasInUse;
1260 irpWasInUse = InterlockedCompareExchange(&info->MediaChangeIrpInUse, 0, 1);
1261 #if _MSC_FULL_VER != 13009111 // This compiler always takes the wrong path here.
1262 NT_ASSERT(irpWasInUse);
1263 #endif
1264#else
1265 InterlockedCompareExchange(&info->MediaChangeIrpInUse, 0, 1);
1266#endif
1267 }
1268
1269 //
1270 // now send it again before we release our last remove lock
1271 //
1272
1273 if (retryImmediately) {
1274 ClasspSendMediaStateIrp(fdoExtension, info, 0);
1275 }
1276 else {
1277 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_MCN, "ClasspMediaChangeDetectionCompletion - not retrying immediately"));
1278 }
1279
1280 //
1281 // release the temporary remove lock
1282 //
1283
1284 ClassReleaseRemoveLock(DeviceObject, (PVOID)(&uniqueValue));
1285 }
1286
1287 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_MCN, "< ClasspMediaChangeDetectionCompletion"));
1288
1290}
1291
1292/*++////////////////////////////////////////////////////////////////////////////
1293
1294ClasspSendTestUnitIrp() - ISSUE-2000/02/20-henrygab - not documented
1295
1296Routine Description:
1297
1298 This routine
1299
1300Arguments:
1301
1302 DeviceObject -
1303 Irp -
1304
1305Return Value:
1306
1307
1308--*/
1309PIRP
1314)
1315{
1318 PIO_STACK_LOCATION irpStack;
1319 PIO_STACK_LOCATION nextIrpStack;
1321 PCDB cdb;
1322 PIRP irp;
1323 PVOID buffer;
1325 ULONG srbFlags;
1326 ULONG timeOutValue;
1327 UCHAR cdbLength;
1329 ULONG dataTransferLength;
1330
1331 //
1332 // Setup the IRP to perform a test unit ready.
1333 //
1334
1335 irp = Info->MediaChangeIrp;
1336
1337 if (irp == NULL) {
1338 NT_ASSERT(irp);
1339 return NULL;
1340 }
1341
1342 //
1343 // don't keep sending this if the device is being removed.
1344 //
1345
1347 if (status == REMOVE_COMPLETE) {
1349 return NULL;
1350 }
1351 else if (status == REMOVE_PENDING) {
1352 ClassReleaseRemoveLock(FdoExtension->DeviceObject, irp);
1353 return NULL;
1354 }
1355 else {
1357 }
1358
1360
1361 /*
1362 * For the driver that creates an IRP, there is no 'current' stack location.
1363 * Step down one IRP stack location so that the extra top one
1364 * becomes our 'current' one.
1365 */
1367
1368 /*
1369 * Cache our device object in the extra top IRP stack location
1370 * so we have it in our completion routine.
1371 */
1373 irpStack->DeviceObject = FdoExtension->DeviceObject;
1374
1375 //
1376 // If the irp is sent down when the volume needs to be
1377 // verified, CdRomUpdateGeometryCompletion won't complete
1378 // it since it's not associated with a thread. Marking
1379 // it to override the verify causes it always be sent
1380 // to the port driver
1381 //
1382
1383 irpStack->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
1384
1385 nextIrpStack = IoGetNextIrpStackLocation(irp);
1387 nextIrpStack->Parameters.Scsi.Srb = &(Info->MediaChangeSrb.Srb);
1388
1389 //
1390 // Prepare the SRB for execution.
1391 //
1392
1393 buffer = Info->SenseBuffer;
1394 bufferLength = Info->SenseBufferLength;
1395
1398
1399 srbFlags = FdoExtension->SrbFlags;
1400 SET_FLAG(srbFlags, Info->SrbFlags);
1401
1402 timeOutValue = FdoExtension->TimeOutValue * 2;
1403 if (timeOutValue == 0) {
1404
1405 if (FdoExtension->TimeOutValue == 0) {
1406
1407 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN,
1408 "ClassSendTestUnitIrp: FdoExtension->TimeOutValue "
1409 "is set to zero?! -- resetting to 10\n"));
1410 timeOutValue = 10 * 2; // reasonable default
1411
1412 } else {
1413
1414 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN,
1415 "ClassSendTestUnitIrp: Someone set "
1416 "srb->TimeOutValue to zero?! -- resetting to %x\n",
1417 FdoExtension->TimeOutValue * 2));
1418 timeOutValue = FdoExtension->TimeOutValue * 2;
1419
1420 }
1421
1422 }
1423
1424 if (!UseGesn) {
1425 nextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_NONE;
1426 irp->MdlAddress = NULL;
1427
1429
1430 //
1431 // Set SRB_FLAGS_NO_KEEP_AWAKE for non-cdrom devices if these requests should
1432 // not prevent devices from going to sleep.
1433 //
1434 if ((FdoExtension->DeviceObject->DeviceType != FILE_DEVICE_CD_ROM) &&
1435 (ClasspScreenOff == TRUE)) {
1437 }
1438
1439 cdbLength = 6;
1440 dataBuffer = NULL;
1441 dataTransferLength = 0;
1442
1443 } else {
1444 NT_ASSERT(Info->Gesn.Buffer);
1445
1446 nextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
1447 irp->MdlAddress = Info->Gesn.Mdl;
1448
1449 SET_FLAG(srbFlags, SRB_FLAGS_DATA_IN);
1450 cdbLength = 10;
1451 dataBuffer = Info->Gesn.Buffer;
1452 dataTransferLength = Info->Gesn.BufferSize;
1453 timeOutValue = GESN_TIMEOUT_VALUE; // much shorter timeout for GESN
1454
1455 }
1456
1457 //
1458 // SRB used here is the MediaChangeSrb in _MEDIA_CHANGE_DETECTION_INFO.
1459 //
1460 srb = nextIrpStack->Parameters.Scsi.Srb;
1461 if (FdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1462 srbEx = (PSTORAGE_REQUEST_BLOCK)nextIrpStack->Parameters.Scsi.Srb;
1463
1467 1,
1469 if (!NT_SUCCESS(status)) {
1470 // should not happen
1472 return NULL;
1473 }
1474
1475 srbEx->RequestTag = SP_UNTAGGED;
1476 srbEx->RequestAttribute = SRB_SIMPLE_TAG_REQUEST;
1477 srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI;
1478 srbEx->SrbStatus = 0;
1479 srbEx->OriginalRequest = irp;
1480 srbEx->SrbFlags = srbFlags;
1481 srbEx->TimeOutValue = timeOutValue;
1482 srbEx->DataBuffer = dataBuffer;
1483 srbEx->DataTransferLength = dataTransferLength;
1484
1485 SrbSetScsiStatus(srbEx, 0);
1488 SrbSetCdbLength(srbEx, cdbLength);
1489
1490 cdb = SrbGetCdb(srbEx);
1491
1492 } else {
1493 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
1494
1495 srb->QueueTag = SP_UNTAGGED;
1497 srb->Length = sizeof(SCSI_REQUEST_BLOCK);
1499 srb->SenseInfoBuffer = buffer;
1501 srb->SrbStatus = 0;
1502 srb->ScsiStatus = 0;
1503 srb->OriginalRequest = irp;
1504
1505 srb->SrbFlags = srbFlags;
1506 srb->TimeOutValue = timeOutValue;
1507 srb->CdbLength = cdbLength;
1508 srb->DataBuffer = dataBuffer;
1509 srb->DataTransferLength = dataTransferLength;
1510
1511 cdb = (PCDB) &srb->Cdb[0];
1512
1513 }
1514
1515 if (cdb) {
1516 if (!UseGesn) {
1517 cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
1518 } else {
1519 cdb->GET_EVENT_STATUS_NOTIFICATION.OperationCode =
1521 cdb->GET_EVENT_STATUS_NOTIFICATION.Immediate = 1;
1522 cdb->GET_EVENT_STATUS_NOTIFICATION.EventListLength[0] =
1523 (UCHAR)((Info->Gesn.BufferSize) >> 8);
1524 cdb->GET_EVENT_STATUS_NOTIFICATION.EventListLength[1] =
1525 (UCHAR)((Info->Gesn.BufferSize) & 0xff);
1526 cdb->GET_EVENT_STATUS_NOTIFICATION.NotificationClassRequest =
1527 Info->Gesn.EventMask;
1528 }
1529 }
1530
1533 srb,
1534 TRUE,
1535 TRUE,
1536 TRUE);
1537
1538 return irp;
1539
1540}
1541
1542/*++////////////////////////////////////////////////////////////////////////////
1543
1544ClasspSendMediaStateIrp() - ISSUE-2000/02/20-henrygab - not documented
1545
1546Routine Description:
1547
1548 This routine
1549
1550Arguments:
1551
1552 DeviceObject -
1553 Irp -
1554
1555Return Value:
1556
1557--*/
1558VOID
1562 IN ULONG CountDown
1563 )
1564{
1565 BOOLEAN requestPending = FALSE;
1566 LONG irpInUse;
1567
1568 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_MCN, "> ClasspSendMediaStateIrp"));
1569
1570 if (((FdoExtension->CommonExtension.CurrentState != IRP_MN_START_DEVICE) ||
1571 (FdoExtension->DevicePowerState != PowerDeviceD0)
1572 ) &&
1573 (!Info->MediaChangeIrpLost)) {
1574
1575 //
1576 // the device may be stopped, powered down, or otherwise queueing io,
1577 // so should not timeout the autorun irp (yet) -- set to zero ticks.
1578 // scattered code relies upon this to not prematurely "lose" an
1579 // autoplay irp that was queued.
1580 //
1581
1582 Info->MediaChangeIrpTimeInUse = 0;
1583 }
1584
1585 //
1586 // if the irp is not in use, mark it as such.
1587 //
1588
1589 irpInUse = InterlockedCompareExchange(&Info->MediaChangeIrpInUse, 1, 0);
1590
1591 if (irpInUse) {
1592
1593 LONG timeInUse;
1594
1595 timeInUse = InterlockedIncrement(&Info->MediaChangeIrpTimeInUse);
1596
1597 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_MCN, "ClasspSendMediaStateIrp: irp in use for "
1598 "%x seconds when synchronizing for MCD\n", timeInUse));
1599
1600 if (Info->MediaChangeIrpLost == FALSE) {
1601
1602 if (timeInUse > MEDIA_CHANGE_TIMEOUT_TIME) {
1603
1604 //
1605 // currently set to five minutes. hard to imagine a drive
1606 // taking that long to spin up.
1607 //
1608
1609 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN,
1610 "CdRom%d: Media Change Notification has lost "
1611 "it's irp and doesn't know where to find it. "
1612 "Leave it alone and it'll come home dragging "
1613 "it's stack behind it.\n",
1614 FdoExtension->DeviceNumber));
1615 Info->MediaChangeIrpLost = TRUE;
1616 }
1617 }
1618
1619 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_MCN, "< ClasspSendMediaStateIrp - irpInUse"));
1620 return;
1621
1622 }
1623
1624 TRY {
1625
1626 if (Info->MediaChangeDetectionDisableCount != 0) {
1627 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "ClassCheckMediaState: device %p has "
1628 " detection disabled \n", FdoExtension->DeviceObject));
1629 LEAVE;
1630 }
1631
1632 if (FdoExtension->DevicePowerState != PowerDeviceD0) {
1633
1634 //
1635 // It's possible that the device went to D3 while the screen was
1636 // off so we need to make sure that we send the IRP regardless
1637 // of the device's power state in order to wake the device back
1638 // up when the screen comes back on.
1639 // When the screen is off we set the SRB_FLAG_NO_KEEP_AWAKE flag
1640 // so that the lower driver does not power-up the device for this
1641 // request. When the screen comes back on, however, we want to
1642 // resume checking for media presence so we no longer set the flag.
1643 // When the device is in D3 we also stop the polling timer as well.
1644 //
1645
1646 //
1647 // NOTE: we don't increment the time in use until our power state
1648 // changes above. this way, we won't "lose" the autoplay irp.
1649 // it's up to the lower driver to determine if powering up is a
1650 // good idea.
1651 //
1652
1653 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
1654 "ClassCheckMediaState: device %p needs to powerup "
1655 "to handle this io (may take a few extra seconds).\n",
1656 FdoExtension->DeviceObject));
1657 }
1658
1659 Info->MediaChangeIrpTimeInUse = 0;
1660 Info->MediaChangeIrpLost = FALSE;
1661
1662 if (CountDown == 0) {
1663
1664 PIRP irp;
1665
1666 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
1667 "ClassCheckMediaState: timer expired\n"));
1668
1669 if (Info->MediaChangeDetectionDisableCount != 0) {
1670 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
1671 "ClassCheckMediaState: detection disabled\n"));
1672 LEAVE;
1673 }
1674
1675 //
1676 // Prepare the IRP for the test unit ready
1677 //
1678
1680 Info,
1681 Info->Gesn.Supported);
1682
1683 //
1684 // Issue the request.
1685 //
1686
1687 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_MCN,
1688 "ClasspSendMediaStateIrp: Device %p getting TUR "
1689 " irp %p\n", FdoExtension->DeviceObject, irp));
1690
1691 if (irp == NULL) {
1692 LEAVE;
1693 }
1694
1695
1696 //
1697 // note: if we send it to the class dispatch routines, there is
1698 // a timing window here (since they grab the remove lock)
1699 // where we'd be removed. ELIMINATE the window by grabbing
1700 // the lock ourselves above and sending it to the lower
1701 // device object directly or to the device's StartIo
1702 // routine (which doesn't acquire the lock).
1703 //
1704
1705 requestPending = TRUE;
1706
1707 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_MCN, " ClasspSendMediaStateIrp - calling IoCallDriver."));
1708 IoCallDriver(FdoExtension->CommonExtension.LowerDeviceObject, irp);
1709 }
1710
1711 } FINALLY {
1712
1713 if(requestPending == FALSE) {
1714#if DBG
1715 irpInUse = InterlockedCompareExchange(&Info->MediaChangeIrpInUse, 0, 1);
1716 #if _MSC_FULL_VER != 13009111 // This compiler always takes the wrong path here.
1717 NT_ASSERT(irpInUse);
1718 #endif
1719#else
1720 InterlockedCompareExchange(&Info->MediaChangeIrpInUse, 0, 1);
1721#endif
1722 }
1723
1724 }
1725
1726 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_MCN, "< ClasspSendMediaStateIrp"));
1727
1728 return;
1729} // end ClasspSendMediaStateIrp()
1730
1731/*++////////////////////////////////////////////////////////////////////////////
1732
1733ClassCheckMediaState()
1734
1735Routine Description:
1736
1737 This routine is called by the class driver to test for a media change
1738 condition and/or poll for disk failure prediction. It should be called
1739 from the class driver's IO timer routine once per second.
1740
1741Arguments:
1742
1743 FdoExtension - the device extension
1744
1745Return Value:
1746
1747 none
1748
1749--*/
1750VOID
1751NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
1754 )
1755{
1756 PMEDIA_CHANGE_DETECTION_INFO info = FdoExtension->MediaChangeDetectionInfo;
1757 LONG countDown;
1758
1759 if(info == NULL) {
1760 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
1761 "ClassCheckMediaState: detection not enabled\n"));
1762 return;
1763 }
1764
1765 //
1766 // Media change support is active and the IRP is waiting. Decrement the
1767 // timer. There is no MP protection on the timer counter. This code
1768 // is the only code that will manipulate the timer counter and only one
1769 // instance of it should be running at any given time.
1770 //
1771
1772 countDown = InterlockedDecrement(&(info->MediaChangeCountDown));
1773
1774 //
1775 // Try to acquire the media change event. If we can't do it immediately
1776 // then bail out and assume the caller will try again later.
1777 //
1779 info,
1780 countDown);
1781
1782 return;
1783} // end ClassCheckMediaState()
1784
1785/*++////////////////////////////////////////////////////////////////////////////
1786
1787ClassResetMediaChangeTimer()
1788
1789Routine Description:
1790
1791 Resets the media change count down timer to the default number of seconds.
1792
1793Arguments:
1794
1795 FdoExtension - the device to reset the timer for
1796
1797Return Value:
1798
1799 None
1800
1801--*/
1802VOID
1803NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
1806 )
1807{
1808 PMEDIA_CHANGE_DETECTION_INFO info = FdoExtension->MediaChangeDetectionInfo;
1809
1810 if(info != NULL) {
1811 InterlockedExchange(&(info->MediaChangeCountDown),
1813 }
1814 return;
1815} // end ClassResetMediaChangeTimer()
1816
1817/*++////////////////////////////////////////////////////////////////////////////
1818
1819ClasspInitializePolling() - ISSUE-2000/02/20-henrygab - not documented
1820
1821Routine Description:
1822
1823 This routine
1824
1825Arguments:
1826
1827 DeviceObject -
1828 Irp -
1829
1830Return Value:
1831
1832--*/
1837 )
1838{
1839 PDEVICE_OBJECT fdo = FdoExtension->DeviceObject;
1840
1842 PIRP irp;
1843
1844 PAGED_CODE();
1845
1846 if (FdoExtension->MediaChangeDetectionInfo != NULL) {
1847 return STATUS_SUCCESS;
1848 }
1849
1850 info = ExAllocatePoolWithTag(NonPagedPoolNx,
1853
1854 if (info != NULL) {
1856
1857 FdoExtension->KernelModeMcnContext.FileObject = (PVOID)-1;
1858 FdoExtension->KernelModeMcnContext.DeviceObject = (PVOID)-1;
1859 FdoExtension->KernelModeMcnContext.LockCount = 0;
1860 FdoExtension->KernelModeMcnContext.McnDisableCount = 0;
1861
1862 /*
1863 * Allocate an IRP to carry the Test-Unit-Ready.
1864 * Allocate an extra IRP stack location
1865 * so we can cache our device object in the top location.
1866 */
1867 irp = IoAllocateIrp((CCHAR)(fdo->StackSize+1), FALSE);
1868
1869 if (irp != NULL) {
1870
1871 PVOID buffer;
1872 BOOLEAN GesnSupported = FALSE;
1873
1875 NonPagedPoolNxCacheAligned,
1878
1879 if (buffer != NULL) {
1880
1881 info->MediaChangeIrp = irp;
1882 info->SenseBuffer = buffer;
1883 info->SenseBufferLength = SENSE_BUFFER_SIZE_EX;
1884
1885 //
1886 // Set default values for the media change notification
1887 // configuration.
1888 //
1889
1890 info->MediaChangeCountDown = MEDIA_CHANGE_DEFAULT_TIME;
1891 info->MediaChangeDetectionDisableCount = 0;
1892
1893 //
1894 // Assume that there is initially no media in the device
1895 // only notify upper layers if there is something there
1896 //
1897
1898 info->MediaChangeDetectionState = MediaUnknown;
1899
1900 info->MediaChangeIrpTimeInUse = 0;
1901 info->MediaChangeIrpLost = FALSE;
1902
1903 //
1904 // setup all extra flags we'll be setting for this irp
1905 //
1906 info->SrbFlags = 0;
1907 if (AllowDriveToSleep) {
1909 }
1913
1914 KeInitializeMutex(&info->MediaChangeMutex, 0x100);
1915
1916 //
1917 // It is ok to support media change events on this
1918 // device.
1919 //
1920
1921 FdoExtension->MediaChangeDetectionInfo = info;
1922
1923 //
1924 // NOTE: the DeviceType is FILE_DEVICE_CD_ROM even
1925 // when the device supports DVD (no need to
1926 // check for FILE_DEVICE_DVD, as it's not a
1927 // valid check).
1928 //
1929
1930 if (FdoExtension->DeviceObject->DeviceType == FILE_DEVICE_CD_ROM) {
1931
1933
1934 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
1935 "ClasspInitializePolling: Testing for GESN\n"));
1937 if (NT_SUCCESS(status)) {
1938 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
1939 "ClasspInitializePolling: GESN available "
1940 "for %p\n", FdoExtension->DeviceObject));
1941 NT_ASSERT(info->Gesn.Supported );
1942 NT_ASSERT(info->Gesn.Buffer != NULL);
1943 NT_ASSERT(info->Gesn.BufferSize != 0);
1944 NT_ASSERT(info->Gesn.EventMask != 0);
1945 GesnSupported = TRUE;
1946 } else {
1947 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
1948 "ClasspInitializePolling: GESN *NOT* available "
1949 "for %p\n", FdoExtension->DeviceObject));
1950 }
1951 }
1952
1953 if (GesnSupported == FALSE) {
1954 NT_ASSERT(info->Gesn.Supported == 0);
1955 NT_ASSERT(info->Gesn.Buffer == NULL);
1956 NT_ASSERT(info->Gesn.BufferSize == 0);
1957 NT_ASSERT(info->Gesn.EventMask == 0);
1958 info->Gesn.Supported = 0; // just in case....
1959 }
1960
1961 //
1962 // Register for screen state notification. Will use this to
1963 // determine user presence.
1964 //
1967 &GUID_CONSOLE_DISPLAY_STATE,
1969 NULL,
1971 }
1972
1973 return STATUS_SUCCESS;
1974 }
1975
1976 IoFreeIrp(irp);
1977 }
1978
1979 FREE_POOL(info);
1980 }
1981
1982 //
1983 // nothing to free here
1984 //
1986
1987} // end ClasspInitializePolling()
1988
1993 )
1994{
1997 PSTORAGE_DEVICE_DESCRIPTOR deviceDescriptor;
1999 PIRP irp;
2000 KEVENT event;
2001 BOOLEAN retryImmediately;
2002 ULONG i;
2003 ULONG atapiResets;
2004 ULONG srbFlags;
2005
2006 PAGED_CODE();
2007 NT_ASSERT(Info == FdoExtension->MediaChangeDetectionInfo);
2008
2009 //
2010 // read if we already know the abilities of the device
2011 //
2012
2013 ClassGetDeviceParameter(FdoExtension,
2016 (PULONG)&detectionState);
2017
2018 if (detectionState == ClassDetectionUnsupported) {
2019 goto ExitWithError;
2020 }
2021
2022 //
2023 // check if the device has a hack flag saying never to try this.
2024 //
2025
2026 if (TEST_FLAG(FdoExtension->PrivateFdoData->HackFlags,
2028
2029 ClassSetDeviceParameter(FdoExtension,
2033 goto ExitWithError;
2034
2035 }
2036
2037
2038 //
2039 // else go through the process since we allocate buffers and
2040 // get all sorts of device settings.
2041 //
2042
2043 if (Info->Gesn.Buffer == NULL) {
2044 Info->Gesn.Buffer = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
2046 '??cS');
2047 }
2048 if (Info->Gesn.Buffer == NULL) {
2050 goto ExitWithError;
2051 }
2052 if (Info->Gesn.Mdl != NULL) {
2053 IoFreeMdl(Info->Gesn.Mdl);
2054 }
2055 Info->Gesn.Mdl = IoAllocateMdl(Info->Gesn.Buffer,
2057 FALSE, FALSE, NULL);
2058 if (Info->Gesn.Mdl == NULL) {
2060 goto ExitWithError;
2061 }
2062
2064 Info->Gesn.BufferSize = GESN_BUFFER_SIZE;
2065 Info->Gesn.EventMask = 0;
2066
2067 //
2068 // all items are prepared to use GESN (except the event mask, so don't
2069 // optimize this part out!).
2070 //
2071 // now see if it really works. we have to loop through this because
2072 // many SAMSUNG (and one COMPAQ) drives timeout when requesting
2073 // NOT_READY events, even when the IMMEDIATE bit is set. :(
2074 //
2075 // using a drive list is cumbersome, so this might fix the problem.
2076 //
2077
2078 deviceDescriptor = FdoExtension->DeviceDescriptor;
2079 atapiResets = 0;
2080 retryImmediately = TRUE;
2081 for (i = 0; i < 16 && retryImmediately == TRUE; i++) {
2082
2084 if (irp == NULL) {
2086 goto ExitWithError;
2087 }
2088
2089 if (Info->MediaChangeSrb.Srb.Function == SRB_FUNCTION_STORAGE_REQUEST_BLOCK) {
2090 srbFlags = Info->MediaChangeSrb.SrbEx.SrbFlags;
2091 } else {
2092 srbFlags = Info->MediaChangeSrb.Srb.SrbFlags;
2093 }
2095
2096 //
2097 // replace the completion routine with a different one this time...
2098 //
2099
2103 &event,
2104 TRUE, TRUE, TRUE);
2105
2106 status = IoCallDriver(FdoExtension->CommonExtension.LowerDeviceObject, irp);
2107
2108 if (status == STATUS_PENDING) {
2110 Executive,
2111 KernelMode,
2112 FALSE,
2113 NULL);
2115 }
2116 ClassReleaseRemoveLock(FdoExtension->DeviceObject, irp);
2117
2118 if (SRB_STATUS(Info->MediaChangeSrb.Srb.SrbStatus) != SRB_STATUS_SUCCESS) {
2119
2121 irp,
2122 &(Info->MediaChangeSrb.Srb),
2124 0,
2125 0,
2126 &status,
2127 NULL);
2128 }
2129
2130 if ((deviceDescriptor->BusType == BusTypeAtapi) &&
2131 (Info->MediaChangeSrb.Srb.SrbStatus == SRB_STATUS_BUS_RESET)
2132 ) {
2133
2134 //
2135 // ATAPI unfortunately returns SRB_STATUS_BUS_RESET instead
2136 // of SRB_STATUS_TIMEOUT, so we cannot differentiate between
2137 // the two. if we get this status four time consecutively,
2138 // stop trying this command. it is too late to change ATAPI
2139 // at this point, so special-case this here. (07/10/2001)
2140 // NOTE: any value more than 4 may cause the device to be
2141 // marked missing.
2142 //
2143
2144 atapiResets++;
2145 if (atapiResets >= 4) {
2147 goto ExitWithError;
2148 }
2149 }
2150
2151 if (status == STATUS_DATA_OVERRUN) {
2153 }
2154
2156 (status == STATUS_TIMEOUT) ||
2159 ) {
2160
2161 //
2162 // with these error codes, we don't ever want to try this command
2163 // again on this device, since it reacts poorly.
2164 //
2165
2166 ClassSetDeviceParameter(FdoExtension,
2170 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN,
2171 "Classpnp => GESN test failed %x for fdo %p\n",
2172 status, FdoExtension->DeviceObject));
2173 goto ExitWithError;
2174
2175
2176 }
2177
2178 if (!NT_SUCCESS(status)) {
2179
2180 //
2181 // this may be other errors that should not disable GESN
2182 // for all future start_device calls.
2183 //
2184
2185 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN,
2186 "Classpnp => GESN test failed %x for fdo %p\n",
2187 status, FdoExtension->DeviceObject));
2188 goto ExitWithError;
2189 }
2190
2191 if (i == 0) {
2192
2193 //
2194 // the first time, the request was just retrieving a mask of
2195 // available bits. use this to mask future requests.
2196 //
2197
2199
2200 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2201 "Classpnp => Fdo %p supports event mask %x\n",
2202 FdoExtension->DeviceObject, header->SupportedEventClasses));
2203
2204
2205 if (TEST_FLAG(header->SupportedEventClasses,
2207 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2208 "Classpnp => GESN supports MCN\n"));
2209 }
2210 if (TEST_FLAG(header->SupportedEventClasses,
2212 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2213 "Classpnp => GESN supports DeviceBusy\n"));
2214 }
2215 if (TEST_FLAG(header->SupportedEventClasses,
2217
2218 if (TEST_FLAG(FdoExtension->PrivateFdoData->HackFlags,
2220 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2221 "Classpnp => GESN supports OpChange, but "
2222 "must ignore these events for compatibility\n"));
2223 CLEAR_FLAG(header->SupportedEventClasses,
2225 } else {
2226 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2227 "Classpnp => GESN supports OpChange\n"));
2228 }
2229 }
2230 Info->Gesn.EventMask = header->SupportedEventClasses;
2231
2232 //
2233 // realistically, we are only considering the following events:
2234 // EXTERNAL REQUEST - this is being tested for play/stop/etc.
2235 // MEDIA STATUS - autorun and ejection requests.
2236 // DEVICE BUSY - to allow us to predict when media will be ready.
2237 // therefore, we should not bother querying for the other,
2238 // unknown events. clear all but the above flags.
2239 //
2240
2241 Info->Gesn.EventMask &=
2246
2247
2248 //
2249 // HACKHACK - REF #0001
2250 // Some devices will *never* report an event if we've also requested
2251 // that it report lower-priority events. this is due to a
2252 // misunderstanding in the specification wherein a "No Change" is
2253 // interpreted to be a real event. what should occur is that the
2254 // device should ignore "No Change" events when multiple event types
2255 // are requested unless there are no other events waiting. this
2256 // greatly reduces the number of requests that the host must send
2257 // to determine if an event has occurred. Since we must work on all
2258 // drives, default to enabling the hack until we find evidence of
2259 // proper firmware.
2260 //
2261 if (Info->Gesn.EventMask == 0) {
2262
2263 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2264 "Classpnp => GESN supported, but not mask we care "
2265 "about (%x) for FDO %p\n",
2266 header->SupportedEventClasses,
2267 FdoExtension->DeviceObject));
2268 goto ExitWithError;
2269
2270 } else if (CountOfSetBitsUChar(Info->Gesn.EventMask) == 1) {
2271
2272 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2273 "Classpnp => GESN hack not required for FDO %p\n",
2274 FdoExtension->DeviceObject));
2275
2276 } else {
2277
2278 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2279 "Classpnp => GESN hack enabled for FDO %p\n",
2280 FdoExtension->DeviceObject));
2281 Info->Gesn.HackEventMask = 1;
2282
2283 }
2284
2285 } else {
2286
2287 //
2288 // not the first time looping through, so interpret the results.
2289 //
2290
2292 (PVOID)Info->Gesn.Buffer,
2293 &retryImmediately);
2294
2295 if (!NT_SUCCESS(status)) {
2296
2297 //
2298 // This drive does not support GESN correctly
2299 //
2300
2301 ClassSetDeviceParameter(FdoExtension,
2305 goto ExitWithError;
2306 }
2307 }
2308
2309 } // end loop of GESN requests....
2310
2311 //
2312 // we can only use this if it can be relied upon for media changes,
2313 // since we are (by definition) no longer going to be polling via
2314 // a TEST_UNIT_READY irp, and drives will not report UNIT ATTENTION
2315 // for this command (although a filter driver, such as one for burning
2316 // cd's, might still fake those errors).
2317 //
2318 // since we also rely upon NOT_READY events to change the cursor
2319 // into a "wait" cursor; GESN is still more reliable than other
2320 // methods, and includes eject button requests, so we'll use it
2321 // without DEVICE_BUSY in Windows Vista.
2322 //
2323
2324 if (TEST_FLAG(Info->Gesn.EventMask, NOTIFICATION_MEDIA_STATUS_CLASS_MASK)) {
2325
2326 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2327 "Classpnp => Enabling GESN support for fdo %p\n",
2328 FdoExtension->DeviceObject));
2329 Info->Gesn.Supported = TRUE;
2330
2331 ClassSetDeviceParameter(FdoExtension,
2335
2336 return STATUS_SUCCESS;
2337
2338 }
2339
2340 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2341 "Classpnp => GESN available but not enabled for fdo %p\n",
2342 FdoExtension->DeviceObject));
2343 goto ExitWithError;
2344
2345 // fall through...
2346
2347ExitWithError:
2348 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN,
2349 "Classpnp => GESN support detection failed for fdo %p with status %08x\n",
2350 FdoExtension->DeviceObject, status));
2351
2352
2353 if (Info->Gesn.Mdl) {
2354 IoFreeMdl(Info->Gesn.Mdl);
2355 Info->Gesn.Mdl = NULL;
2356 }
2357 FREE_POOL(Info->Gesn.Buffer);
2358 Info->Gesn.Supported = 0;
2359 Info->Gesn.EventMask = 0;
2360 Info->Gesn.BufferSize = 0;
2361 return STATUS_NOT_SUPPORTED;
2362
2363}
2364
2365
2366//
2367// Work item to set the hack flag in the registry to disable GESN
2368// on devices that sends too many events
2369//
2370
2371VOID
2372NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
2376 )
2377{
2378 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
2380
2381 PAGED_CODE();
2382
2383 //
2384 // Set the hack flag in the registry
2385 //
2386 ClassSetDeviceParameter(fdoExtension,
2392}
2393
2394/*++////////////////////////////////////////////////////////////////////////////
2395
2396ClassInitializeTestUnitPolling()
2397
2398Routine Description:
2399
2400 This routine will initialize MCN regardless of the settings stored
2401 in the registry. This should be used with caution, as some devices
2402 react badly to constant io. (i.e. never spin down, continuously cycling
2403 media in changers, ejection of media, etc.) It is highly suggested to
2404 use ClassInitializeMediaChangeDetection() instead.
2405
2406Arguments:
2407
2408 FdoExtension is the device to poll
2409
2410 AllowDriveToSleep says whether to attempt to allow the drive to sleep
2411 or not. This only affects system-known spin down states, so if a
2412 drive spins itself down, this has no effect until the system spins
2413 it down.
2414
2415Return Value:
2416
2417--*/
2420NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
2421ClassInitializeTestUnitPolling(
2424 )
2425{
2427} // end ClassInitializeTestUnitPolling()
2428
2429/*++////////////////////////////////////////////////////////////////////////////
2430
2431ClassInitializeMediaChangeDetection()
2432
2433Routine Description:
2434
2435 This routine checks to see if it is safe to initialize MCN (the back end
2436 to autorun) for a given device. It will then check the device-type wide
2437 key "Autorun" in the service key (for legacy reasons), and then look in
2438 the device-specific key to potentially override that setting.
2439
2440 If MCN is to be enabled, all neccessary structures and memory are
2441 allocated and initialized.
2442
2443 This routine MUST be called only from the ClassInit() callback.
2444
2445Arguments:
2446
2447 FdoExtension - the device to initialize MCN for, if appropriate
2448
2449 EventPrefix - unused, legacy argument. Set to zero.
2450
2451Return Value:
2452
2453--*/
2455VOID
2456NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
2457ClassInitializeMediaChangeDetection(
2460 )
2461{
2462 PDEVICE_OBJECT fdo = FdoExtension->DeviceObject;
2464
2465 PCLASS_DRIVER_EXTENSION driverExtension = ClassGetDriverExtension(
2466 fdo->DriverObject);
2467
2468 BOOLEAN disabledForBadHardware;
2469 BOOLEAN disabled;
2470 BOOLEAN instanceOverride;
2471
2473
2474 PAGED_CODE();
2475
2476 //
2477 // NOTE: This assumes that ClassInitializeMediaChangeDetection is always
2478 // called in the context of the ClassInitDevice callback. If called
2479 // after then this check will have already been made and the
2480 // once a second timer will not have been enabled.
2481 //
2482
2485 &(driverExtension->RegistryPath)
2486 );
2487
2488 if (disabledForBadHardware) {
2489 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2490 "ClassInitializeMCN: Disabled due to hardware"
2491 "limitations for this device"));
2492 return;
2493 }
2494
2495 //
2496 // autorun should now be enabled by default for all media types.
2497 //
2498
2501 &(driverExtension->RegistryPath)
2502 );
2503
2504 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2505 "ClassInitializeMCN: Class MCN is %s\n",
2506 (disabled ? "disabled" : "enabled")));
2507
2510 &instanceOverride); // default value
2511
2512 if (!NT_SUCCESS(status)) {
2513 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2514 "ClassInitializeMCN: Instance using default\n"));
2515 } else {
2516 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2517 "ClassInitializeMCN: Instance override: %s MCN\n",
2518 (instanceOverride ? "Enabling" : "Disabling")));
2519 disabled = !instanceOverride;
2520 }
2521
2522 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2523 "ClassInitializeMCN: Instance MCN is %s\n",
2524 (disabled ? "disabled" : "enabled")));
2525
2526 if (disabled) {
2527 return;
2528 }
2529
2530 //
2531 // Do not allow drive to sleep for all types of devices initially.
2532 // For non-cdrom devices, allow devices to go to sleep if it's
2533 // unlikely a media change will occur (e.g. user not present).
2534 //
2536
2537 return;
2538} // end ClassInitializeMediaChangeDetection()
2539
2540/*++////////////////////////////////////////////////////////////////////////////
2541
2542ClasspMediaChangeDeviceInstanceOverride()
2543
2544Routine Description:
2545
2546 The user can override the global setting to enable or disable Autorun on a
2547 specific cdrom device via the control panel. This routine checks and/or
2548 sets this value.
2549
2550Arguments:
2551
2552 FdoExtension - the device to set/get the value for
2553 Value - the value to use in a set
2554 SetValue - whether to set the value
2555
2556Return Value:
2557
2558 TRUE - Autorun is disabled
2559 FALSE - Autorun is not disabled (Default)
2560
2561--*/
2566 )
2567{
2568 HANDLE deviceParameterHandle = NULL; // cdrom instance key
2569 HANDLE driverParameterHandle = NULL; // cdrom specific key
2570 RTL_QUERY_REGISTRY_TABLE queryTable[3];
2571 OBJECT_ATTRIBUTES objectAttributes;
2572 UNICODE_STRING subkeyName;
2574 ULONG alwaysEnable = FALSE;
2575 ULONG alwaysDisable = FALSE;
2576 ULONG i;
2577
2578 PAGED_CODE();
2579
2580 TRY {
2581
2585 &deviceParameterHandle
2586 );
2587 if (!NT_SUCCESS(status)) {
2588
2589 //
2590 // this can occur when a new device is added to the system
2591 // this is due to cdrom.sys being an 'essential' driver
2592 //
2593 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2594 "ClassMediaChangeDeviceInstanceDisabled: "
2595 "Could not open device registry key [%lx]\n", status));
2596 LEAVE;
2597 }
2598
2600 InitializeObjectAttributes(&objectAttributes,
2601 &subkeyName,
2603 deviceParameterHandle,
2605
2606 status = ZwCreateKey(&driverParameterHandle,
2607 KEY_READ,
2608 &objectAttributes,
2609 0,
2612 NULL);
2613
2614 if (!NT_SUCCESS(status)) {
2615 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2616 "ClassMediaChangeDeviceInstanceDisabled: "
2617 "subkey could not be created. %lx\n", status));
2618 LEAVE;
2619 }
2620
2621 //
2622 // Default to not changing autorun behavior, based upon setting
2623 // registryValue to zero.
2624 //
2625
2626 for (i=0;i<2;i++) {
2627
2628 RtlZeroMemory(&queryTable[0], sizeof(queryTable));
2629
2632 queryTable[0].DefaultLength = 0;
2633
2634 if (i==0) {
2636 queryTable[0].EntryContext = &alwaysDisable;
2637 queryTable[0].DefaultData = &alwaysDisable;
2638 } else {
2640 queryTable[0].EntryContext = &alwaysEnable;
2641 queryTable[0].DefaultData = &alwaysEnable;
2642 }
2643
2644 //
2645 // don't care if it succeeds, since we set defaults above
2646 //
2647
2649 (PWSTR)driverParameterHandle,
2650 queryTable,
2651 NULL,
2652 NULL);
2653 }
2654
2655 } FINALLY {
2656
2657 if (driverParameterHandle) ZwClose(driverParameterHandle);
2658 if (deviceParameterHandle) ZwClose(deviceParameterHandle);
2659
2660 }
2661
2662 if (alwaysEnable && alwaysDisable) {
2663
2664 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2665 "ClassMediaChangeDeviceInstanceDisabled: %s selected\n",
2666 "Both Enable and Disable set -- DISABLE"));
2669 *Enabled = FALSE;
2670
2671 } else if (alwaysDisable) {
2672
2673 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2674 "ClassMediaChangeDeviceInstanceDisabled: %s selected\n",
2675 "DISABLE"));
2678 *Enabled = FALSE;
2679
2680 } else if (alwaysEnable) {
2681
2682 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2683 "ClassMediaChangeDeviceInstanceDisabled: %s selected\n",
2684 "ENABLE"));
2687 *Enabled = TRUE;
2688
2689 } else {
2690
2691 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2692 "ClassMediaChangeDeviceInstanceDisabled: %s selected\n",
2693 "DEFAULT"));
2695
2696 }
2697
2698 return status;
2699
2700} // end ClasspMediaChangeDeviceInstanceOverride()
2701
2702/*++////////////////////////////////////////////////////////////////////////////
2703
2704ClasspIsMediaChangeDisabledDueToHardwareLimitation()
2705
2706Routine Description:
2707
2708 The key AutoRunAlwaysDisable contains a MULTI_SZ of hardware IDs for
2709 which to never enable MediaChangeNotification.
2710
2711 The user can override the global setting to enable or disable Autorun on a
2712 specific cdrom device via the control panel.
2713
2714Arguments:
2715
2716 FdoExtension -
2717 RegistryPath - pointer to the unicode string inside
2718 ...\CurrentControlSet\Services\Cdrom
2719
2720Return Value:
2721
2722 TRUE - no autorun.
2723 FALSE - Autorun may be enabled
2724
2725--*/
2726BOOLEAN
2730 )
2731{
2732 PSTORAGE_DEVICE_DESCRIPTOR deviceDescriptor = FdoExtension->DeviceDescriptor;
2733 OBJECT_ATTRIBUTES objectAttributes = {0};
2734 HANDLE serviceKey = NULL;
2735 RTL_QUERY_REGISTRY_TABLE parameters[2] = {0};
2736
2737 UNICODE_STRING deviceUnicodeString;
2738 ANSI_STRING deviceString;
2739 ULONG mediaChangeNotificationDisabled = FALSE;
2740
2742
2743
2744 PAGED_CODE();
2745
2746 //
2747 // open the service key.
2748 //
2749
2750 InitializeObjectAttributes(&objectAttributes,
2753 NULL,
2754 NULL);
2755
2756 status = ZwOpenKey(&serviceKey,
2757 KEY_READ,
2758 &objectAttributes);
2759
2761
2762
2763 if(!NT_SUCCESS(status)) {
2764
2765 //
2766 // always take the safe path. if we can't open the service key,
2767 // disable autorun
2768 //
2769
2770 return TRUE;
2771
2772 }
2773
2774 TRY {
2775 //
2776 // Determine if drive is in a list of those requiring
2777 // autorun to be disabled. this is stored in a REG_MULTI_SZ
2778 // named AutoRunAlwaysDisable. this is required as some autochangers
2779 // must load the disc to reply to ChkVerify request, causing them
2780 // to cycle discs continuously.
2781 //
2782
2783 PWSTR nullMultiSz;
2784 PUCHAR vendorId;
2785 PUCHAR productId;
2786 PUCHAR revisionId;
2787 ULONG length;
2788 ULONG offset;
2789
2790 deviceString.Buffer = NULL;
2791 deviceUnicodeString.Buffer = NULL;
2792
2793 //
2794 // there may be nothing to check against
2795 //
2796
2797 if ((deviceDescriptor->VendorIdOffset == 0) &&
2798 (deviceDescriptor->ProductIdOffset == 0)) {
2799 LEAVE;
2800 }
2801
2802 length = 0;
2803
2804 if (deviceDescriptor->VendorIdOffset == 0) {
2805 vendorId = NULL;
2806 } else {
2807 vendorId = (PUCHAR) deviceDescriptor + deviceDescriptor->VendorIdOffset;
2808 length = (ULONG)strlen((PCSZ)vendorId);
2809 }
2810
2811 if ( deviceDescriptor->ProductIdOffset == 0 ) {
2812 productId = NULL;
2813 } else {
2814 productId = (PUCHAR)deviceDescriptor + deviceDescriptor->ProductIdOffset;
2815 length += (ULONG)strlen((PCSZ)productId);
2816 }
2817
2818 if ( deviceDescriptor->ProductRevisionOffset == 0 ) {
2819 revisionId = NULL;
2820 } else {
2821 revisionId = (PUCHAR) deviceDescriptor + deviceDescriptor->ProductRevisionOffset;
2822 length += (ULONG)strlen((PCSZ)revisionId);
2823 }
2824
2825 //
2826 // allocate a buffer for the string
2827 //
2828
2829 deviceString.Length = (USHORT)( length );
2830 deviceString.MaximumLength = deviceString.Length + 1;
2831 deviceString.Buffer = (PCHAR)ExAllocatePoolWithTag( NonPagedPoolNx,
2832 deviceString.MaximumLength,
2834 );
2835 if (deviceString.Buffer == NULL) {
2836 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2837 "ClassMediaChangeDisabledForHardware: Unable to alloc "
2838 "string buffer\n" ));
2839 LEAVE;
2840 }
2841
2842 //
2843 // copy strings to the buffer
2844 //
2845 offset = 0;
2846
2847 if (vendorId != NULL) {
2848 RtlCopyMemory(deviceString.Buffer + offset,
2849 vendorId,
2850 strlen((PCSZ)vendorId));
2851 offset += (ULONG)strlen((PCSZ)vendorId);
2852 }
2853
2854 if ( productId != NULL ) {
2855 RtlCopyMemory(deviceString.Buffer + offset,
2856 productId,
2857 strlen((PCSZ)productId));
2858 offset += (ULONG)strlen((PCSZ)productId);
2859 }
2860 if ( revisionId != NULL ) {
2861 RtlCopyMemory(deviceString.Buffer + offset,
2862 revisionId,
2863 strlen((PCSZ)revisionId));
2864 offset += (ULONG)strlen((PCSZ)revisionId);
2865 }
2866
2867 NT_ASSERT(offset == deviceString.Length);
2868
2869#ifdef _MSC_VER
2870 #pragma warning(suppress:6386) // Not an issue as deviceString.Buffer is of size deviceString.MaximumLength, which is equal to (deviceString.Length + 1)
2871#endif
2872 deviceString.Buffer[deviceString.Length] = '\0'; // Null-terminated
2873
2874 //
2875 // convert to unicode as registry deals with unicode strings
2876 //
2877
2878 status = RtlAnsiStringToUnicodeString( &deviceUnicodeString,
2879 &deviceString,
2880 TRUE
2881 );
2882 if (!NT_SUCCESS(status)) {
2883 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2884 "ClassMediaChangeDisabledForHardware: cannot convert "
2885 "to unicode %lx\n", status));
2886 LEAVE;
2887 }
2888
2889 //
2890 // query the value, setting valueFound to true if found
2891 //
2892 nullMultiSz = L"\0";
2894 parameters[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
2895 parameters[0].Name = L"AutoRunAlwaysDisable";
2896 parameters[0].EntryContext = &mediaChangeNotificationDisabled;
2897 parameters[0].DefaultType = REG_MULTI_SZ;
2898 parameters[0].DefaultData = nullMultiSz;
2899 parameters[0].DefaultLength = 0;
2900
2902 serviceKey,
2903 parameters,
2904 &deviceUnicodeString,
2905 NULL);
2906
2907 if ( !NT_SUCCESS(status) ) {
2908 LEAVE;
2909 }
2910
2911 } FINALLY {
2912
2913 FREE_POOL( deviceString.Buffer );
2914 if (deviceUnicodeString.Buffer != NULL) {
2915 RtlFreeUnicodeString( &deviceUnicodeString );
2916 }
2917
2918 ZwClose(serviceKey);
2919 }
2920
2921 if (mediaChangeNotificationDisabled) {
2922 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "ClassMediaChangeDisabledForHardware: "
2923 "Device is on disable list\n"));
2924 return TRUE;
2925 }
2926 return FALSE;
2927
2928} // end ClasspIsMediaChangeDisabledDueToHardwareLimitation()
2929
2930/*++////////////////////////////////////////////////////////////////////////////
2931
2932ClasspIsMediaChangeDisabledForClass()
2933
2934Routine Description:
2935
2936 The user must specify that AutoPlay is to run on the platform
2937 by setting the registry value HKEY_LOCAL_MACHINE\System\CurrentControlSet\
2938 Services<SERVICE>\Autorun:REG_DWORD:1.
2939
2940 The user can override the global setting to enable or disable Autorun on a
2941 specific cdrom device via the control panel.
2942
2943Arguments:
2944
2945 FdoExtension -
2946 RegistryPath - pointer to the unicode string inside
2947 ...\CurrentControlSet\Services\Cdrom
2948
2949Return Value:
2950
2951 TRUE - Autorun is disabled for this class
2952 FALSE - Autorun is enabled for this class
2953
2954--*/
2955BOOLEAN
2959 )
2960{
2961 OBJECT_ATTRIBUTES objectAttributes = {0};
2962 HANDLE serviceKey = NULL;
2963 HANDLE parametersKey = NULL;
2964 RTL_QUERY_REGISTRY_TABLE parameters[3] = {0};
2965
2966 UNICODE_STRING paramStr;
2967
2968 //
2969 // Default to ENABLING MediaChangeNotification (!)
2970 //
2971
2972 ULONG mcnRegistryValue = 1;
2973
2975
2976
2977 PAGED_CODE();
2978
2979 //
2980 // open the service key.
2981 //
2982
2983 InitializeObjectAttributes(&objectAttributes,
2986 NULL,
2987 NULL);
2988
2989 status = ZwOpenKey(&serviceKey,
2990 KEY_READ,
2991 &objectAttributes);
2992
2994
2995 if(!NT_SUCCESS(status)) {
2996
2997 //
2998 // return the default value, which is the
2999 // inverse of the registry setting default
3000 // since this routine asks if it's disabled
3001 //
3002
3003 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "ClassCheckServiceMCN: Defaulting to %s\n",
3004 (mcnRegistryValue ? "Enabled" : "Disabled")));
3005 return (BOOLEAN)(!mcnRegistryValue);
3006
3007 }
3008
3009 //
3010 // Open the parameters key (if any) beneath the services key.
3011 //
3012
3013 RtlInitUnicodeString(&paramStr, L"Parameters");
3014
3015 InitializeObjectAttributes(&objectAttributes,
3016 &paramStr,
3018 serviceKey,
3019 NULL);
3020
3021 status = ZwOpenKey(&parametersKey,
3022 KEY_READ,
3023 &objectAttributes);
3024
3025 if (!NT_SUCCESS(status)) {
3026 parametersKey = NULL;
3027 }
3028
3029
3030
3031 //
3032 // Check for the Autorun value.
3033 //
3034
3035 parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
3036 parameters[0].Name = L"Autorun";
3037 parameters[0].EntryContext = &mcnRegistryValue;
3039 parameters[0].DefaultData = &mcnRegistryValue;
3040 parameters[0].DefaultLength = sizeof(ULONG);
3041
3042 // ignore failures
3044 serviceKey,
3045 parameters,
3046 NULL,
3047 NULL);
3048
3049 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "ClassCheckServiceMCN: "
3050 "<Service>/Autorun flag = %d\n", mcnRegistryValue));
3051
3052 if(parametersKey != NULL) {
3053
3054 // ignore failures
3056 parametersKey,
3057 parameters,
3058 NULL,
3059 NULL);
3060 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "ClassCheckServiceMCN: "
3061 "<Service>/Parameters/Autorun flag = %d\n",
3062 mcnRegistryValue));
3063 ZwClose(parametersKey);
3064
3065 }
3066 ZwClose(serviceKey);
3067
3068 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "ClassCheckServiceMCN: "
3069 "Autoplay for device %p is %s\n",
3070 FdoExtension->DeviceObject,
3071 (mcnRegistryValue ? "on" : "off")
3072 ));
3073
3074 //
3075 // return if it is _disabled_, which is the
3076 // inverse of the registry setting
3077 //
3078
3079 return (BOOLEAN)(!mcnRegistryValue);
3080} // end ClasspIsMediaChangeDisabledForClass()
3081
3082/*++////////////////////////////////////////////////////////////////////////////
3083
3084ClassEnableMediaChangeDetection() ISSUE-2000/02/20-henrygab - why public?
3085ClassEnableMediaChangeDetection() ISSUE-2000/02/20-henrygab - not documented
3086
3087Routine Description:
3088
3089 This routine
3090
3091Arguments:
3092
3093 DeviceObject -
3094 Irp -
3095
3096Return Value:
3097
3098--*/
3100VOID
3101NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
3102ClassEnableMediaChangeDetection(
3104 )
3105{
3106 PMEDIA_CHANGE_DETECTION_INFO info = FdoExtension->MediaChangeDetectionInfo;
3107 LONG oldCount;
3108
3109 PAGED_CODE();
3110
3111 if(info == NULL) {
3112 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
3113 "ClassEnableMediaChangeDetection: not initialized\n"));
3114 return;
3115 }
3116
3117 (VOID)KeWaitForMutexObject(&info->MediaChangeMutex,
3119 KernelMode,
3120 FALSE,
3121 NULL);
3122
3123 oldCount = --info->MediaChangeDetectionDisableCount;
3124
3125 NT_ASSERT(oldCount >= 0);
3126
3127 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "ClassEnableMediaChangeDetection: Disable count "
3128 "reduced to %d - ",
3129 info->MediaChangeDetectionDisableCount));
3130
3131 if(oldCount == 0) {
3132
3133 //
3134 // We don't know what state the media is in anymore.
3135 //
3136
3139 FALSE
3140 );
3141
3142 //
3143 // Reset the MCN timer.
3144 //
3145
3147
3148 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "MCD is enabled\n"));
3149
3150 } else {
3151
3152 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "MCD still disabled\n"));
3153
3154 }
3155
3156
3157 //
3158 // Let something else run.
3159 //
3160
3161 KeReleaseMutex(&info->MediaChangeMutex, FALSE);
3162
3163 return;
3164} // end ClassEnableMediaChangeDetection()
3165
3166/*++////////////////////////////////////////////////////////////////////////////
3167
3168ClassDisableMediaChangeDetection() ISSUE-2000/02/20-henrygab - why public?
3169ClassDisableMediaChangeDetection() ISSUE-2000/02/20-henrygab - not documented
3170
3171Routine Description:
3172
3173 This routine
3174
3175Arguments:
3176
3177 DeviceObject -
3178 Irp -
3179
3180Return Value:
3181
3182--*/
3184
3186VOID
3187NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
3188ClassDisableMediaChangeDetection(
3190 )
3191{
3192 PMEDIA_CHANGE_DETECTION_INFO info = FdoExtension->MediaChangeDetectionInfo;
3193
3194 PAGED_CODE();
3195
3196 if(info == NULL) {
3197 return;
3198 }
3199
3200 (VOID)KeWaitForMutexObject(&info->MediaChangeMutex,
3202 KernelMode,
3203 FALSE,
3204 NULL);
3205
3206 info->MediaChangeDetectionDisableCount++;
3207
3208 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "ClassDisableMediaChangeDetection: "
3209 "disable count is %d\n",
3210 info->MediaChangeDetectionDisableCount));
3211
3212 KeReleaseMutex(&info->MediaChangeMutex, FALSE);
3213
3214 return;
3215} // end ClassDisableMediaChangeDetection()
3216
3217/*++////////////////////////////////////////////////////////////////////////////
3218
3219ClassCleanupMediaChangeDetection() ISSUE-2000/02/20-henrygab - why public?!
3220
3221Routine Description:
3222
3223 This routine will cleanup any resources allocated for MCN. It is called
3224 by classpnp during remove device, and therefore is not typically required
3225 by external drivers.
3226
3227Arguments:
3228
3229Return Value:
3230
3231--*/
3233VOID
3234NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
3235ClassCleanupMediaChangeDetection(
3237 )
3238{
3239 PMEDIA_CHANGE_DETECTION_INFO info = FdoExtension->MediaChangeDetectionInfo;
3240
3241 PAGED_CODE()
3242
3243 if(info == NULL) {
3244 return;
3245 }
3246
3247 FdoExtension->MediaChangeDetectionInfo = NULL;
3248
3249 if (info->Gesn.Mdl) {
3250 IoFreeMdl(info->Gesn.Mdl);
3251 }
3252 FREE_POOL(info->Gesn.Buffer);
3253 IoFreeIrp(info->MediaChangeIrp);
3254 FREE_POOL(info->SenseBuffer);
3255 FREE_POOL(info);
3256 return;
3257} // end ClassCleanupMediaChangeDetection()
3258
3259/*++////////////////////////////////////////////////////////////////////////////
3260
3261ClasspMcnControl() - ISSUE-2000/02/20-henrygab - not documented
3262
3263Routine Description:
3264
3265 This routine
3266
3267Arguments:
3268
3269 DeviceObject -
3270 Irp -
3271
3272Return Value:
3273
3274--*/
3278 IN PIRP Irp,
3280 )
3281{
3282 PCOMMON_DEVICE_EXTENSION commonExtension =
3284
3286 PPREVENT_MEDIA_REMOVAL request = Irp->AssociatedIrp.SystemBuffer;
3287
3288 PFILE_OBJECT fileObject = irpStack->FileObject;
3289 PFILE_OBJECT_EXTENSION fsContext = NULL;
3290
3292
3293 PAGED_CODE();
3294
3295 //
3296 // Check to make sure we have a file object extension to keep track of this
3297 // request. If not we'll fail it before synchronizing.
3298 //
3299
3300 TRY {
3301
3302 if(fileObject != NULL) {
3303 fsContext = ClassGetFsContext(commonExtension, fileObject);
3304 }else if(Irp->RequestorMode == KernelMode) { // && fileObject == NULL
3305 fsContext = &FdoExtension->KernelModeMcnContext;
3306 }
3307
3308 if (fsContext == NULL) {
3309
3310 //
3311 // This handle isn't setup correctly. We can't let the
3312 // operation go.
3313 //
3314
3316 LEAVE;
3317 }
3318
3319 if(request->PreventMediaRemoval) {
3320
3321 //
3322 // This is a lock command. Reissue the command in case bus or
3323 // device was reset and the lock was cleared.
3324 //
3325
3326 ClassDisableMediaChangeDetection(FdoExtension);
3327 InterlockedIncrement((volatile LONG *)&(fsContext->McnDisableCount));
3328
3329 } else {
3330
3331 if(fsContext->McnDisableCount == 0) {
3333 LEAVE;
3334 }
3335
3336 InterlockedDecrement((volatile LONG *)&(fsContext->McnDisableCount));
3337 ClassEnableMediaChangeDetection(FdoExtension);
3338 }
3339
3340 } FINALLY {
3341
3342 Irp->IoStatus.Status = status;
3343
3344 FREE_POOL(Srb);
3345
3346 ClassReleaseRemoveLock(FdoExtension->DeviceObject, Irp);
3347 ClassCompleteRequest(FdoExtension->DeviceObject,
3348 Irp,
3350 }
3351 return status;
3352} // end ClasspMcnControl(
3353
3354/*++////////////////////////////////////////////////////////////////////////////
3355
3356ClasspMediaChangeRegistryCallBack()
3357
3358Routine Description:
3359
3360 This callback for a registry SZ or MULTI_SZ is called once for each
3361 SZ in the value. It will attempt to match the data with the
3362 UNICODE_STRING passed in as Context, and modify EntryContext if a
3363 match is found. Written for ClasspCheckRegistryForMediaChangeCompletion
3364
3365Arguments:
3366
3367 ValueName - name of the key that was opened
3368 ValueType - type of data stored in the value (REG_SZ for this routine)
3369 ValueData - data in the registry, in this case a wide string
3370 ValueLength - length of the data including the terminating null
3371 Context - unicode string to compare against ValueData
3372 EntryContext - should be initialized to 0, will be set to 1 if match found
3373
3374Return Value:
3375
3376 STATUS_SUCCESS
3377 EntryContext will be 1 if found
3378
3379--*/
3380_Function_class_(RTL_QUERY_REGISTRY_ROUTINE)
3384NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
3392 )
3393{
3394 PULONG valueFound;
3395 PUNICODE_STRING deviceString;
3396 PWSTR keyValue;
3397
3398 PAGED_CODE();
3400
3401 if (ValueData == NULL ||
3402 Context == NULL ||
3403 EntryContext == NULL) {
3405 }
3406
3407 //
3408 // if we have already set the value to true, exit
3409 //
3410
3411 valueFound = EntryContext;
3412 if ((*valueFound) != 0) {
3413 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "ClasspMcnRegCB: already set to true\n"));
3414 return STATUS_SUCCESS;
3415 }
3416
3417 if (ValueLength == sizeof(WCHAR)) {
3418 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN, "ClasspMcnRegCB: NULL string should "
3419 "never be passed to registry call-back!\n"));
3420 return STATUS_SUCCESS;
3421 }
3422
3423
3424 //
3425 // if the data is not a terminated string, exit
3426 //
3427
3428 if (ValueType != REG_SZ) {
3429 return STATUS_SUCCESS;
3430 }
3431
3432 deviceString = Context;
3433 keyValue = ValueData;
3434 ValueLength -= sizeof(WCHAR); // ignore the null character
3435
3436 //
3437 // do not compare more memory than is in deviceString
3438 //
3439
3440 if (ValueLength > deviceString->Length) {
3441 ValueLength = deviceString->Length;
3442 }
3443
3444 //
3445 // if the strings match, disable autorun
3446 //
3447
3448 if (RtlCompareMemory(deviceString->Buffer, keyValue, ValueLength) == ValueLength) {
3449 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "ClasspRegMcnCB: Match found\n"));
3450 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "ClasspRegMcnCB: DeviceString at %p\n",
3451 deviceString->Buffer));
3452 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "ClasspRegMcnCB: KeyValue at %p\n",
3453 keyValue));
3454 (*valueFound) = TRUE;
3455 }
3456
3457 return STATUS_SUCCESS;
3458} // end ClasspMediaChangeRegistryCallBack()
3459
3460#if (NTDDI_VERSION >= NTDDI_WINBLUE)
3461VOID
3465)
3466{
3467 KDPC dummyDpc = { 0 };
3468
3470 //
3471 // This is just a wrapper around ClasspTimerTick that allows us to make
3472 // the TickTimer a no-wake EX_TIMER.
3473 // We pass in a dummy DPC b/c ClasspTimerTick expects a non-NULL parameter
3474 // for the DPC. However, ClasspTimerTick does not actually reference it.
3475 //
3476 ClasspTimerTick(&dummyDpc, Context, NULL, NULL);
3477}
3478#endif
3479
3480/*++////////////////////////////////////////////////////////////////////////////
3481
3482ClasspTimerTick() - ISSUE-2000/02/20-henrygab - not documented
3483
3484Routine Description:
3485
3486 This routine
3487
3488Arguments:
3489
3490 DeviceObject -
3491 Irp -
3492
3493Return Value:
3494
3495--*/
3496_Function_class_(KDEFERRED_ROUTINE)
3501VOID
3502NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
3504 _In_ PKDPC Dpc,
3508 )
3509{
3511 PCOMMON_DEVICE_EXTENSION commonExtension;
3513 ULONG isRemoved;
3514
3518
3519 NT_ASSERT(fdoExtension != NULL);
3520 _Analysis_assume_(fdoExtension != NULL);
3521
3522 commonExtension = &fdoExtension->CommonExtension;
3523 DeviceObject = fdoExtension->DeviceObject;
3524 NT_ASSERT(commonExtension->IsFdo);
3525
3526 //
3527 // Do any media change work
3528 //
3529#ifdef _MSC_VER
3530#pragma warning(suppress:4054) // okay to type cast function pointer to PIRP for this use case
3531#endif
3533
3534 //
3535 // We stop the timer before deleting the device. It's safe to keep going
3536 // if the flag value is REMOVE_PENDING because the removal thread will be
3537 // blocked trying to stop the timer.
3538 //
3539
3540 NT_ASSERT(isRemoved != REMOVE_COMPLETE);
3541
3542 //
3543 // This routine is reasonably safe even if the device object has a pending
3544 // remove
3545
3546 if (!isRemoved) {
3547
3549
3550 //
3551 // Do any media change detection work
3552 //
3553
3554 if ((fdoExtension->MediaChangeDetectionInfo != NULL) &&
3555 (fdoExtension->FunctionSupportInfo->AsynchronousNotificationSupported == FALSE)) {
3556
3557 ClassCheckMediaState(fdoExtension);
3558
3559 }
3560
3561 //
3562 // Do any failure prediction work
3563 //
3564 if ((info != NULL) && (info->Method != FailurePredictionNone)) {
3565
3566 ULONG countDown;
3567
3568 if (ClasspCanSendPollingIrp(fdoExtension)) {
3569
3570 //
3571 // Synchronization is not required here since the Interlocked
3572 // locked instruction guarantees atomicity. Other code that
3573 // resets CountDown uses InterlockedExchange which is also
3574 // atomic.
3575 //
3576 countDown = InterlockedDecrement((volatile LONG *)&info->CountDown);
3577 if (countDown == 0) {
3578
3579 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "ClasspTimerTick: Send FP irp for %p\n",
3580 DeviceObject));
3581
3582 if(info->WorkQueueItem == NULL) {
3583
3584 info->WorkQueueItem =
3585 IoAllocateWorkItem(fdoExtension->DeviceObject);
3586
3587 if(info->WorkQueueItem == NULL) {
3588
3589 //
3590 // Set the countdown to one minute in the future.
3591 // we'll try again then in the hopes there's more
3592 // free memory.
3593 //
3594
3595 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN, "ClassTimerTick: Couldn't allocate "
3596 "item - try again in one minute\n"));
3597 InterlockedExchange((volatile LONG *)&info->CountDown, 60);
3598
3599 } else {
3600
3601 //
3602 // Grab the remove lock so that removal will block
3603 // until the work item is done.
3604 //
3605
3607 info->WorkQueueItem);
3608
3609 IoQueueWorkItem(info->WorkQueueItem,
3612 info);
3613 }
3614
3615 } else {
3616
3617 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "ClasspTimerTick: Failure "
3618 "Prediction work item is "
3619 "already active for device %p\n",
3620 DeviceObject));
3621
3622 }
3623 } // end (countdown == 0)
3624
3625 } else {
3626 //
3627 // If device is sleeping then just rearm polling timer
3628 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "ClassTimerTick, SHHHH!!! device is %p is sleeping\n",
3629 DeviceObject));
3630 }
3631
3632 } // end failure prediction polling
3633
3634 //
3635 // Give driver a chance to do its own specific work
3636 //
3637
3638 if (commonExtension->DriverExtension->InitData.ClassTick != NULL) {
3639
3641
3642 } // end device specific tick handler
3643 } // end check for removed
3644
3645#ifdef _MSC_VER
3646#pragma warning(suppress:4054) // okay to type cast function pointer to PIRP for this use case
3647#endif
3649} // end ClasspTimerTick()
3650
3651#if (NTDDI_VERSION >= NTDDI_WINBLUE)
3652BOOLEAN
3655)
3656/*
3657Routine Description:
3658
3659 Updates the no-wake timer's tolerance based on system state.
3660
3661 If the timer is not allocated, initialized, or enabled then this function
3662 does nothing.
3663
3664 If the timer is enabled but the no-wake tolerance has *not* changed from
3665 its previous value then this function does nothing.
3666
3667 If the timer is enabled and the no-wake tolerance has changed from its
3668 previous value then this function *will* set/reset the tick timer.
3669
3670Arguments:
3671
3672 FdoExtension for the device that has the timer whose tolerance needs updating.
3673
3674Returns:
3675
3676 TRUE if the timer was set/reset.
3677 FALSE if the timer was not set/reset.
3678
3679*/
3680{
3681 PCLASS_PRIVATE_FDO_DATA fdoData = NULL;
3682
3683 if (FdoExtension->CommonExtension.IsFdo) {
3684 fdoData = FdoExtension->PrivateFdoData;
3685 }
3686
3687 if (fdoData != NULL &&
3688 fdoData->TickTimer != NULL &&
3689 fdoData->TimerInitialized &&
3690 fdoData->TickTimerEnabled) {
3691
3692 LONGLONG noWakeTolerance = TICK_TIMER_DELAY_IN_MSEC * (10 * 1000);
3693
3694 //
3695 // Set the no-wake tolerance to "unlimited" if the conditions below
3696 // are met. An "unlimited" no-wake tolerance means that the timer
3697 // will *never* wake the processor if the processor is in a
3698 // low-power state.
3699 // 1. The screen is off.
3700 // 2. The class driver is *not* a consumer of the tick timer (ClassTick is NULL).
3701 // 3. This is a disk device.
3702 // Otherwise the tolerance is set to the normal, default tolerable delay.
3703 //
3704 if (ClasspScreenOff &&
3705 FdoExtension->CommonExtension.DriverExtension->InitData.ClassTick == NULL &&
3706 FdoExtension->DeviceObject->DeviceType == FILE_DEVICE_DISK) {
3707 noWakeTolerance = EX_TIMER_UNLIMITED_TOLERANCE;
3708 }
3709
3710 //
3711 // The new tolerance is different from the current tolerance so we need
3712 // to set/reset the timer with the new tolerance value.
3713 //
3714 if (fdoData->CurrentNoWakeTolerance != noWakeTolerance) {
3715 EXT_SET_PARAMETERS parameters;
3716 LONGLONG period = TICK_TIMER_PERIOD_IN_MSEC * (10 * 1000); // Convert to units of 100ns.
3717 LONGLONG dueTime = period * (-1); // Negative sign indicates dueTime is relative.
3718
3719 ExInitializeSetTimerParameters(&parameters);
3720 parameters.NoWakeTolerance = noWakeTolerance;
3721 fdoData->CurrentNoWakeTolerance = noWakeTolerance;
3722
3723 ExSetTimer(fdoData->TickTimer,
3724 dueTime,
3725 period,
3726 &parameters);
3727
3728 return TRUE;
3729 }
3730 }
3731
3732 return FALSE;
3733}
3734#endif
3735
3739)
3740/*
3741Routine Description:
3742
3743 This routine will attempt to initialize the tick timer.
3744 The caller should call ClasspEnableTmer() to actually start the timer.
3745
3746 If the caller just needs to check if the timer is initialized, the caller
3747 should simply check FdoExtension->PrivateFdoData->TimerInitialized rather
3748 than call this function.
3749
3750 The caller should subsequently call ClasspDeleteTimer() when they are done
3751 with the timer.
3752
3753Arguments:
3754
3755 FdoExtension
3756
3757Return Value:
3758
3759 STATUS_SUCCESS if the timer is initialized (the timer may already have been
3760 initialized by a previous call).
3761 A non-success status if the timer is not initialized.
3762
3763*/
3764{
3765 PCLASS_PRIVATE_FDO_DATA fdoData = NULL;
3766
3767 if (FdoExtension->CommonExtension.IsFdo) {
3768 fdoData = FdoExtension->PrivateFdoData;
3769 }
3770
3771 if (fdoData == NULL) {
3772 return STATUS_UNSUCCESSFUL;
3773 }
3774
3775 if (fdoData->TimerInitialized == FALSE) {
3776#if (NTDDI_VERSION >= NTDDI_WINBLUE)
3777 NT_ASSERT(fdoData->TickTimer == NULL);
3778 //
3779 // The tick timer is a no-wake timer, which means it will not wake
3780 // the processor while the processor is in a low power state until
3781 // the timer's no-wake tolerance is reached.
3782 //
3784 if (fdoData->TickTimer == NULL) {
3786 }
3787#else
3788 KeInitializeDpc(&fdoData->TickTimerDpc, ClasspTimerTick, FdoExtension);
3789 KeInitializeTimer(&fdoData->TickTimer);
3790#endif
3791 fdoData->TimerInitialized = TRUE;
3792 }
3793
3794 return STATUS_SUCCESS;
3795}
3796
3797VOID
3800)
3801/*
3802Routine Description:
3803
3804 This routine will attempt to de-initialize and free the tick timer.
3805 This routine should only be called after a successful call to
3806 ClasspInitializeTimer().
3807
3808Arguments:
3809
3810 FdoExtension
3811
3812Return Value:
3813
3814 None.
3815
3816*/
3817{
3818 PCLASS_PRIVATE_FDO_DATA fdoData = NULL;
3819
3820 if (FdoExtension->CommonExtension.IsFdo) {
3821 fdoData = FdoExtension->PrivateFdoData;
3822 if (fdoData != NULL) {
3823#if (NTDDI_VERSION >= NTDDI_WINBLUE)
3824 if (fdoData->TickTimer != NULL) {
3825 EXT_DELETE_PARAMETERS parameters;
3826 ExInitializeDeleteTimerParameters(&parameters);
3827 ExDeleteTimer(fdoData->TickTimer, TRUE, FALSE, &parameters);
3828 fdoData->TickTimer = NULL;
3829 }
3830#endif
3831 fdoData->TimerInitialized = FALSE;
3832 fdoData->TickTimerEnabled = FALSE;
3833 }
3834 }
3835}
3836
3837/*++////////////////////////////////////////////////////////////////////////////
3838
3839ClasspEnableTimer() - ISSUE-2000/02/20-henrygab - not documented
3840
3841Routine Description:
3842
3843 This routine will enable the tick timer. ClasspInitializeTimer() should
3844 first be called to initialize the timer. Use ClasspDisableTimer() to
3845 disable the timer and then call this function to re-enable it.
3846
3847Arguments:
3848
3849 FdoExtension
3850
3851Return Value:
3852
3853 None.
3854
3855--*/
3856VOID
3859 )
3860{
3861 PCLASS_PRIVATE_FDO_DATA fdoData = NULL;
3862
3863 if (FdoExtension->CommonExtension.IsFdo) {
3864 fdoData = FdoExtension->PrivateFdoData;
3865 }
3866
3867 if (fdoData != NULL) {
3868 //
3869 // The timer should have already been initialized, but if that's not
3870 // the case it's not the end of the world. We can attempt to
3871 // initialize it now.
3872 //
3873 NT_ASSERT(fdoData->TimerInitialized);
3874 if (fdoData->TimerInitialized == FALSE) {
3877 if (NT_SUCCESS(status) == FALSE) {
3878 return;
3879 }
3880 }
3881
3882#if (NTDDI_VERSION >= NTDDI_WINBLUE)
3883 if (fdoData->TickTimer != NULL) {
3884 EXT_SET_PARAMETERS parameters;
3885 LONGLONG period = TICK_TIMER_PERIOD_IN_MSEC * (10 * 1000); // Convert to units of 100ns.
3886 LONGLONG dueTime = period * (-1); // Negative sign indicates dueTime is relative.
3887
3888 ExInitializeSetTimerParameters(&parameters);
3889
3890 //
3891 // Set the no-wake tolerance to "unlimited" if the conditions below
3892 // are met. An "unlimited" no-wake tolerance means that the timer
3893 // will *never* wake the processor if the processor is in a
3894 // low-power state.
3895 // 1. The screen is off.
3896 // 2. The class driver is *not* a consumer of the tick timer (ClassTick is NULL).
3897 // 3. This is a disk device.
3898 // Otherwise the tolerance is set to the normal tolerable delay.
3899 //
3900 if (ClasspScreenOff &&
3901 FdoExtension->CommonExtension.DriverExtension->InitData.ClassTick == NULL &&
3902 FdoExtension->DeviceObject->DeviceType == FILE_DEVICE_DISK) {
3904 } else {
3905 parameters.NoWakeTolerance = TICK_TIMER_DELAY_IN_MSEC * (10 * 1000);
3906 }
3907
3908 fdoData->CurrentNoWakeTolerance = parameters.NoWakeTolerance;
3909
3910 ExSetTimer(fdoData->TickTimer,
3911 dueTime,
3912 period,
3913 &parameters);
3914
3915 fdoData->TickTimerEnabled = TRUE;
3916 } else {
3917 NT_ASSERT(fdoData->TickTimer != NULL);
3918 }
3919#else
3920 //
3921 // Start the periodic tick timer using a coalescable timer with some delay
3922 //
3923 {
3925 timeout.QuadPart = TICK_TIMER_PERIOD_IN_MSEC * (10 * 1000) * (-1);
3926 KeSetCoalescableTimer(&fdoData->TickTimer,
3928 &fdoData->TickTimerDpc);
3929 fdoData->TickTimerEnabled = TRUE;
3930 }
3931#endif
3932
3933 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "ClasspEnableTimer: Periodic tick timer enabled "
3934 "for device %p\n", FdoExtension->DeviceObject));
3935
3936 }
3937
3938} // end ClasspEnableTimer()
3939
3940/*++////////////////////////////////////////////////////////////////////////////
3941
3942ClasspDisableTimer() - ISSUE-2000/02/20-henrygab - not documented
3943
3944Routine Description:
3945
3946 This routine
3947
3948Arguments:
3949
3950 FdoExtension
3951
3952Return Value:
3953
3954--*/
3955VOID
3958 )
3959{
3960 PCLASS_PRIVATE_FDO_DATA fdoData = NULL;
3961
3962 if (FdoExtension->CommonExtension.IsFdo) {
3963 fdoData = FdoExtension->PrivateFdoData;
3964 }
3965
3966 if (fdoData && fdoData->TimerInitialized == TRUE) {
3967
3968 //
3969 // we are only going to stop the actual timer in remove device routine
3970 // or when done transitioning to D3 (timer will be started again when
3971 // done transitioning to D0).
3972 //
3973 // it is the responsibility of the code within the timer routine to
3974 // check if the device is removed and not processing io for the final
3975 // call.
3976 // this keeps the code clean and prevents lots of bugs.
3977 //
3978#if (NTDDI_VERSION >= NTDDI_WINBLUE)
3979 NT_ASSERT(fdoData->TickTimer != NULL);
3980 ExCancelTimer(fdoData->TickTimer, NULL);
3981#else
3982 KeCancelTimer(&fdoData->TickTimer);
3983#endif
3984 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, "ClasspDisableTimer: Periodic tick timer disabled "
3985 "for device %p\n", FdoExtension->DeviceObject));
3986 fdoData->TickTimerEnabled = FALSE;
3987
3988 } else {
3989
3990 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN, "ClasspDisableTimer: Timer never initialized\n"));
3991
3992 }
3993
3994 return;
3995} // end ClasspDisableTimer()
3996
3997/*++////////////////////////////////////////////////////////////////////////////
3998
3999ClasspFailurePredict() - ISSUE-2000/02/20-henrygab - not documented
4000
4001Routine Description:
4002
4003 This routine
4004
4005Arguments:
4006
4007 DeviceObject - Device object
4008 Context - Context (PFAILURE_PREDICTION_INFO)
4009
4010Return Value:
4011
4012Note: this function can be called (via the workitem callback) after the paging device is shut down,
4013 so it must be PAGE LOCKED.
4014--*/
4015VOID
4016NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
4020 )
4021{
4022 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
4023 PIO_WORKITEM workItem;
4024 STORAGE_PREDICT_FAILURE checkFailure = {0};
4025 SCSI_ADDRESS scsiAddress = {0};
4027
4029
4030 if (Info == NULL) {
4031 NT_ASSERT(Info != NULL);
4032 return;
4033 }
4034
4035 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "ClasspFailurePredict: Polling for failure\n"));
4036
4037 //
4038 // Mark the work item as inactive and reset the countdown timer. we
4039 // can't risk freeing the work item until we've released the remove-lock
4040 // though - if we do it might get reused as a tag before we can release
4041 // the lock.
4042 //
4043
4044 InterlockedExchange((volatile LONG *)&Info->CountDown, Info->Period);
4045 workItem = InterlockedExchangePointer((volatile PVOID *)&(Info->WorkQueueItem), NULL);
4046
4047 if (ClasspCanSendPollingIrp(fdoExtension)) {
4048
4049 KEVENT event;
4050 PDEVICE_OBJECT topOfStack;
4051 PIRP irp = NULL;
4052 IO_STATUS_BLOCK ioStatus;
4053 NTSTATUS activateStatus = STATUS_UNSUCCESSFUL;
4054
4055 //
4056 // Take an active reference on the device to ensure it is powered up
4057 // while we do the failure prediction query.
4058 //
4059 if (fdoExtension->FunctionSupportInfo->IdlePower.IdlePowerEnabled) {
4060 activateStatus = ClasspPowerActivateDevice(DeviceObject);
4061 }
4062
4064
4066
4067 //
4068 // Send down irp to see if drive is predicting failure
4069 //
4070
4073 topOfStack,
4074 NULL,
4075 0,
4076 &checkFailure,
4078 FALSE,
4079 &event,
4080 &ioStatus);
4081
4082
4083 if (irp != NULL) {
4084
4085
4086 status = IoCallDriver(topOfStack, irp);
4087 if (status == STATUS_PENDING) {
4089 status = ioStatus.Status;
4090 }
4091
4092
4093 } else {
4095 }
4096
4097 if (NT_SUCCESS(status) && (checkFailure.PredictFailure)) {
4098
4099 checkFailure.PredictFailure = 512;
4100
4101 //
4102 // Send down irp to get scsi address
4103 //
4105
4106 RtlZeroMemory(&scsiAddress, sizeof(SCSI_ADDRESS));
4109 topOfStack,
4110 NULL,
4111 0,
4112 &scsiAddress,
4113 sizeof(SCSI_ADDRESS),
4114 FALSE,
4115 &event,
4116 &ioStatus);
4117
4118 if (irp != NULL) {
4119
4120
4121 status = IoCallDriver(topOfStack, irp);
4122 if (status == STATUS_PENDING) {
4124 }
4125
4126 }
4127
4128 ClassNotifyFailurePredicted(fdoExtension,
4129 (PUCHAR)&checkFailure,
4130 sizeof(checkFailure),
4131 (BOOLEAN)(fdoExtension->FailurePredicted == FALSE),
4132 2,
4133 scsiAddress.PathId,
4134 scsiAddress.TargetId,
4135 scsiAddress.Lun);
4136
4137 fdoExtension->FailurePredicted = TRUE;
4138
4139 }
4140
4141 ObDereferenceObject(topOfStack);
4142
4143 //
4144 // Update the failure prediction query time and release the active
4145 // reference.
4146 //
4147
4148 KeQuerySystemTime(&(Info->LastFailurePredictionQueryTime));
4149
4150 if (NT_SUCCESS(activateStatus)) {
4151 ClasspPowerIdleDevice(DeviceObject);
4152 }
4153 }
4154
4156 IoFreeWorkItem(workItem);
4157 return;
4158} // end ClasspFailurePredict()
4159
4160/*++////////////////////////////////////////////////////////////////////////////
4161
4162ClassNotifyFailurePredicted() ISSUE-alanwar-2000/02/20 - not documented
4163
4164Routine Description:
4165
4166Arguments:
4167
4168Return Value:
4169
4170--*/
4172VOID
4173NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
4174ClassNotifyFailurePredicted(
4182 _In_ UCHAR Lun
4183 )
4184{
4185 PIO_ERROR_LOG_PACKET logEntry;
4186 EVENT_DESCRIPTOR eventDescriptor;
4187 PCLASS_DRIVER_EXTENSION driverExtension;
4188
4189 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "ClasspFailurePredictPollCompletion: Failure predicted for device %p\n", FdoExtension->DeviceObject));
4190
4191 //
4192 // Fire off a WMI event
4193 //
4194 ClassWmiFireEvent(FdoExtension->DeviceObject,
4196 0,
4197 BufferSize,
4198 Buffer);
4199 //
4200 // Log an error into the eventlog
4201 //
4202
4203 if (LogError)
4204 {
4205 logEntry = IoAllocateErrorLogEntry(
4206 FdoExtension->DeviceObject,
4207 sizeof(IO_ERROR_LOG_PACKET) + (3 * sizeof(ULONG)));
4208
4209 if (logEntry != NULL)
4210 {
4211
4212 logEntry->FinalStatus = STATUS_SUCCESS;
4214 logEntry->SequenceNumber = 0;
4217 logEntry->RetryCount = 0;
4219 logEntry->DumpDataSize = 3;
4220
4221 logEntry->DumpData[0] = PathId;
4222 logEntry->DumpData[1] = TargetId;
4223 logEntry->DumpData[2] = Lun;
4224
4225 //
4226 // Write the error log packet.
4227 //
4228
4229 IoWriteErrorLogEntry(logEntry);
4230 }
4231 }
4232
4233 //
4234 // Send ETW event if LogError is TRUE. ClassInterpretSenseInfo sets this
4235 // to FALSE. So if failure is predicted for the first time and UniqueErrorValue
4236 // is 4 (used by ClassInterpretSenseInfo) then send ETW event.
4237 //
4238
4239 if ((LogError == TRUE) ||
4240 ((FdoExtension->FailurePredicted == FALSE) && (UniqueErrorValue == 4))) {
4241
4242#ifdef _MSC_VER
4243#pragma warning(suppress:4054) // okay to type cast function pointer as data pointer for this use case
4244#endif
4245 driverExtension = IoGetDriverObjectExtension(FdoExtension->DeviceObject->DriverObject, CLASS_DRIVER_EXTENSION_KEY);
4246
4247 if ((driverExtension != NULL) && (driverExtension->EtwHandle != 0)) {
4248 EventDescCreate(&eventDescriptor,
4249 1, // Id
4250 0, // Version
4251 0, // Channel
4252 0, // Level
4253 0, // Task
4254 0, // OpCode
4255 0); // Keyword
4256
4257 EtwWrite(driverExtension->EtwHandle,
4258 &eventDescriptor,
4259 NULL,
4260 0,
4261 NULL);
4262 }
4263 }
4264
4265} // end ClassNotifyFailurePredicted()
4266
4267/*++////////////////////////////////////////////////////////////////////////////
4268
4269ClassSetFailurePredictionPoll()
4270
4271Routine Description:
4272
4273 This routine enables polling for failure prediction, setting the timer
4274 to fire every N seconds as specified by the PollingPeriod.
4275
4276Arguments:
4277
4278 FdoExtension - the device to setup failure prediction for.
4279
4280 FailurePredictionMethod - specific failure prediction method to use
4281 if set to FailurePredictionNone, will disable failure detection
4282
4283 PollingPeriod - if 0 then no change to current polling timer
4284
4285Return Value:
4286
4287 NT Status
4288
4289--*/
4292NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
4293ClassSetFailurePredictionPoll(
4297 )
4298{
4301
4302 PAGED_CODE();
4303
4304 if (FdoExtension->FailurePredictionInfo == NULL) {
4305
4307
4308 info = ExAllocatePoolWithTag(NonPagedPoolNx,
4311
4312 if (info == NULL) {
4313
4315
4316 }
4317
4319
4320 info->WorkQueueItem = NULL;
4322
4323 KeQuerySystemTime(&(info->LastFailurePredictionQueryTime));
4324
4325 } else {
4326
4327 //
4328 // FaultPrediction has not been previously initialized, nor
4329 // is it being initialized now. No need to do anything.
4330 //
4331 return STATUS_SUCCESS;
4332
4333 }
4334
4335 FdoExtension->FailurePredictionInfo = info;
4336
4337 } else {
4338
4339 info = FdoExtension->FailurePredictionInfo;
4340
4341 }
4342
4343 /*
4344 * Make sure the user-mode thread is not suspended while we hold the synchronization event.
4345 */
4347
4350 KernelMode,
4351 FALSE,
4352 NULL);
4353
4354
4355 //
4356 // Reset polling period and counter. Setup failure detection type
4357 //
4358
4359 if (PollingPeriod != 0) {
4360
4361 InterlockedExchange((volatile LONG *)&info->Period, PollingPeriod);
4362 }
4363
4364 InterlockedExchange((volatile LONG *)&info->CountDown, info->Period);
4365
4366 info->Method = FailurePredictionMethod;
4368
4370
4371 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "ClassEnableFailurePredictPoll: Enabled for "
4372 "device %p\n", FdoExtension->DeviceObject));
4373
4374 } else {
4375
4377 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "ClassEnableFailurePredictPoll: Disabled for "
4378 "device %p\n", FdoExtension->DeviceObject));
4379 }
4381
4382
4384
4386
4387 return status;
4388} // end ClassSetFailurePredictionPoll()
4389
4390BOOLEAN
4393 )
4394/*
4395Routine Description:
4396 This routine can be used to determine if a failure prediction polling
4397 period has been missed. That is, the time since the last failure
4398 prediction IOCTL has been sent is greater than the failure prediction
4399 polling period. This can happen if failure prediction polling was
4400 disabled, such as when the device is in D3 or when the screen is off.
4401
4402Parameters:
4403 FdoExtension - FDO extension. The caller should make sure the FDO
4404 extension is valid. The FailurePredictionInfo structure should also
4405 be valid and the failure prediction method should not be "none".
4406
4407Returns:
4408 TRUE if there was one or more failure prediction polling periods that was
4409 missed.
4410 FALSE otherwise.
4411*/
4412{
4413 LARGE_INTEGER currentTime;
4414 LARGE_INTEGER timeDifference;
4415 BOOLEAN missedPeriod = FALSE;
4416
4418 NT_ASSERT(FdoExtension->FailurePredictionInfo);
4419 NT_ASSERT(FdoExtension->FailurePredictionInfo->Method != FailurePredictionNone);
4420
4421 //
4422 // Find the difference between the last failure prediction
4423 // query and the current time and convert it to seconds.
4424 //
4425 KeQuerySystemTime(&currentTime);
4426 timeDifference.QuadPart = currentTime.QuadPart - FdoExtension->FailurePredictionInfo->LastFailurePredictionQueryTime.QuadPart;
4427 timeDifference.QuadPart /= (10LL * 1000LL * 1000LL);
4428
4429 if (timeDifference.QuadPart >= FdoExtension->FailurePredictionInfo->Period) {
4430 missedPeriod = TRUE;
4431 }
4432
4433 return missedPeriod;
4434}
4435
4436
#define PAGED_CODE()
unsigned char BOOLEAN
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
#define VOID
Definition: acefi.h:82
#define InterlockedIncrement
Definition: armddk.h:53
#define InterlockedExchange
Definition: armddk.h:54
#define InterlockedDecrement
Definition: armddk.h:52
LONG NTSTATUS
Definition: precomp.h:26
#define MCN_REG_SUBKEY_NAME
Definition: autorun.c:44
#define GESN_TIMEOUT_VALUE
Definition: autorun.c:39
#define MCN_REG_AUTORUN_ENABLE_INSTANCE_NAME
Definition: autorun.c:46
#define GESN_BUFFER_SIZE
Definition: autorun.c:40
#define MAXIMUM_IMMEDIATE_MCN_RETRIES
Definition: autorun.c:43
#define GESN_DEVICE_BUSY_LOWER_THRESHOLD_100_MS
Definition: autorun.c:41
#define MCN_REG_AUTORUN_DISABLE_INSTANCE_NAME
Definition: autorun.c:45
_In_ PSCSI_REQUEST_BLOCK Srb
Definition: cdrom.h:989
#define FREE_POOL(_PoolPtr)
Definition: cdrom.h:782
_In_ BOOLEAN UseGesn
Definition: cdrom.h:1363
#define SRB_CLASS_FLAGS_LOW_PRIORITY
Definition: cdrom.h:162
#define TEST_FLAG(Flags, Bit)
Definition: cdrom.h:1495
#define CLEAR_FLAG(Flags, Bit)
Definition: cdrom.h:1494
FORCEINLINE ULONG CountOfSetBitsUChar(UCHAR _X)
Definition: cdrom.h:1500
#define SET_FLAG(Flags, Bit)
Definition: cdrom.h:1493
#define MEDIA_CHANGE_TIMEOUT_TIME
Definition: cdrom.h:135
#define CLASSP_REG_MMC_DETECTION_VALUE_NAME
Definition: cdromp.h:123
#define FDO_HACK_GESN_IGNORE_OPCHANGE
Definition: cdromp.h:136
@ MediaPresent
Definition: cdromp.h:82
@ MediaNotPresent
Definition: cdromp.h:83
@ MediaUnavailable
Definition: cdromp.h:84
enum _MEDIA_CHANGE_DETECTION_STATE MEDIA_CHANGE_DETECTION_STATE
#define FDO_HACK_GESN_IS_BAD
Definition: cdromp.h:134
#define CLASSP_REG_SUBKEY_NAME
Definition: cdromp.h:120
#define IOCTL_SCSI_EXECUTE_IN
Definition: cdrw_hw.h:1451
#define SCSI_ADSENSE_LUN_NOT_READY
Definition: cdrw_hw.h:1218
#define SCSIOP_GET_EVENT_STATUS
Definition: cdrw_hw.h:934
#define SCSIOP_TEST_UNIT_READY
Definition: cdrw_hw.h:866
struct _SENSE_DATA SENSE_DATA
#define IOCTL_SCSI_EXECUTE_NONE
Definition: cdrw_hw.h:1453
#define SCSI_SENSE_UNIT_ATTENTION
Definition: cdrw_hw.h:1193
#define SCSI_ADSENSE_MEDIUM_CHANGED
Definition: cdrw_hw.h:1288
union _CDB * PCDB
#define SCSI_SENSE_NOT_READY
Definition: cdrw_hw.h:1189
Definition: bufpool.h:45
Definition: Header.h:9
NTSTATUS InitializeStorageRequestBlock(_Inout_bytecount_(ByteSize) PSTORAGE_REQUEST_BLOCK Srb, _In_ USHORT AddressType, _In_ ULONG ByteSize, _In_ ULONG NumSrbExData,...)
Definition: srblib.c:206
struct _FAILURE_PREDICTION_INFO * PFAILURE_PREDICTION_INFO
enum _CLASS_DETECTION_STATE CLASS_DETECTION_STATE
FORCEINLINE BOOLEAN PORT_ALLOCATED_SENSE_EX(_In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, _In_ PSTORAGE_REQUEST_BLOCK_HEADER Srb)
Definition: classp.h:2547
@ ClassDetectionUnknown
Definition: classp.h:445
@ ClassDetectionUnsupported
Definition: classp.h:446
@ ClassDetectionSupported
Definition: classp.h:447
IO_WORKITEM_ROUTINE ClasspUpdateDiskProperties
Definition: classp.h:1714
FORCEINLINE VOID FREE_PORT_ALLOCATED_SENSE_BUFFER_EX(_In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, _In_ PSTORAGE_REQUEST_BLOCK_HEADER Srb)
Definition: classp.h:2560
POWER_SETTING_CALLBACK ClasspPowerSettingCallback
Definition: classp.h:1619
BOOLEAN ClasspIsMediaChangeDisabledForClass(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, IN PUNICODE_STRING RegistryPath)
Definition: autorun.c:2956
BOOLEAN ClasspUpdateTimerNoWakeTolerance(_In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension)
Definition: autorun.c:3653
VOID NTAPI ClassResetMediaChangeTimer(_In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension)
Definition: autorun.c:1804
RTL_QUERY_REGISTRY_ROUTINE ClasspMediaChangeRegistryCallBack
Definition: autorun.c:96
const GUID StoragePredictFailureEventGuid
Definition: autorun.c:40
NTSTATUS ClasspInitializeTimer(_In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension)
Definition: autorun.c:3737
KDEFERRED_ROUTINE ClasspTimerTick
Definition: autorun.c:118
#define TICK_TIMER_DELAY_IN_MSEC
Definition: autorun.c:130
NTSTATUS ClasspMcnControl(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, IN PIRP Irp, IN PSCSI_REQUEST_BLOCK Srb)
Definition: autorun.c:3276
NTSTATUS ClasspInitializePolling(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, IN BOOLEAN AllowDriveToSleep)
Definition: autorun.c:1834
IO_WORKITEM_ROUTINE ClasspDisableGesn
Definition: autorun.c:114
static BOOLEAN ClasspCanSendPollingIrp(_In_ PFUNCTIONAL_DEVICE_EXTENSION fdoExtension)
Definition: autorun.c:61
VOID ClasspSetMediaChangeStateEx(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, IN MEDIA_CHANGE_DETECTION_STATE NewState, IN BOOLEAN Wait, IN BOOLEAN KnownStateChange)
Definition: autorun.c:950
VOID ClasspInternalSetMediaChangeState(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, IN MEDIA_CHANGE_DETECTION_STATE NewState, IN BOOLEAN KnownStateChange)
Definition: autorun.c:798
NTSTATUS ClasspInitializeGesn(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, IN PMEDIA_CHANGE_DETECTION_INFO Info)
Definition: autorun.c:1990
PIRP ClasspPrepareMcnIrp(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, IN PMEDIA_CHANGE_DETECTION_INFO Info, IN BOOLEAN UseGesn)
Definition: autorun.c:1310
VOID ClasspSendMediaStateIrp(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, IN PMEDIA_CHANGE_DETECTION_INFO Info, IN ULONG CountDown)
Definition: autorun.c:1559
VOID ClasspEnableTimer(_In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension)
Definition: autorun.c:3857
ULONG BreakOnMcnDisable
Definition: autorun.c:3183
BOOLEAN ClasspIsMediaChangeDisabledDueToHardwareLimitation(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, IN PUNICODE_STRING RegistryPath)
Definition: autorun.c:2727
VOID ClassSendEjectionNotification(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension)
Definition: autorun.c:155
VOID ClasspDeleteTimer(_In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension)
Definition: autorun.c:3798
EXT_CALLBACK ClasspTimerTickEx
Definition: autorun.c:121
NTSTATUS ClasspMediaChangeDeviceInstanceOverride(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, OUT PBOOLEAN Enabled)
Definition: autorun.c:2563
#define TICK_TIMER_PERIOD_IN_MSEC
Definition: autorun.c:129
IO_COMPLETION_ROUTINE ClasspMediaChangeDetectionCompletion
Definition: autorun.c:116
NTSTATUS ClasspInterpretGesnData(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, IN PNOTIFICATION_EVENT_STATUS_HEADER Header, OUT PBOOLEAN ResendImmediately)
Definition: autorun.c:251
VOID ClasspDisableTimer(_In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension)
Definition: autorun.c:3956
BOOLEAN ClasspScreenOff
Definition: autorun.c:124
BOOLEAN ClasspFailurePredictionPeriodMissed(_In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension)
Definition: autorun.c:4391
IO_WORKITEM_ROUTINE ClasspFailurePredict
Definition: autorun.c:105
VOID NTAPI ClassCheckMediaState(_In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension)
Definition: autorun.c:1752
_In_ ULONG _In_ BOOLEAN _In_ ULONG _In_ UCHAR _In_ UCHAR _In_ UCHAR Lun
Definition: classpnp.h:1315
#define FINALLY
Definition: classpnp.h:116
IO_COMPLETION_ROUTINE ClassSignalCompletion
Definition: classpnp.h:1330
#define LEAVE
Definition: classpnp.h:115
_In_ ULONG _In_ BOOLEAN _In_ ULONG _In_ UCHAR PathId
Definition: classpnp.h:1313
#define CLASS_TAG_AUTORUN_DISABLE
Definition: classpnp.h:77
#define CLASS_TAG_FAILURE_PREDICT
Definition: classpnp.h:84
#define MEDIA_CHANGE_DEFAULT_TIME
Definition: classpnp.h:132
#define ClassAcquireRemoveLock(devobj, tag)
Definition: classpnp.h:100
_In_ FAILURE_PREDICTION_METHOD FailurePredictionMethod
Definition: classpnp.h:1301
_In_ PUCHAR EventPrefix
Definition: classpnp.h:1267
#define CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE
Definition: classpnp.h:695
_In_ ULONG _In_ BOOLEAN _In_ ULONG _In_ UCHAR _In_ UCHAR TargetId
Definition: classpnp.h:1314
_In_ ULONG _In_ BOOLEAN LogError
Definition: classpnp.h:1311
_In_ ULONG _In_ BOOLEAN _In_ ULONG UniqueErrorValue
Definition: classpnp.h:1312
#define DEFAULT_FAILURE_PREDICTION_PERIOD
Definition: classpnp.h:190
#define CLASS_TAG_MEDIA_CHANGE_DETECTION
Definition: classpnp.h:79
#define CLASS_SRB_STORAGE_REQUEST_BLOCK
Definition: classpnp.h:573
#define NO_REMOVE
Definition: classpnp.h:96
_In_ FAILURE_PREDICTION_METHOD _In_ ULONG PollingPeriod
Definition: classpnp.h:1302
_In_ BOOLEAN AllowDriveToSleep
Definition: classpnp.h:1275
#define REMOVE_PENDING
Definition: classpnp.h:97
#define REMOVE_COMPLETE
Definition: classpnp.h:98
_In_ const GUID _In_ ULONG ExtraDataSize
Definition: classpnp.h:1430
FAILURE_PREDICTION_METHOD
Definition: classpnp.h:233
@ FailurePredictionNone
Definition: classpnp.h:234
#define CLASS_DRIVER_EXTENSION_KEY
Definition: classpnp.h:94
_In_ PIRP Irp
Definition: csq.h:116
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
VOID NTAPI KeInitializeDpc(IN PKDPC Dpc, IN PKDEFERRED_ROUTINE DeferredRoutine, IN PVOID DeferredContext)
Definition: dpc.c:712
struct _COMMON_DEVICE_EXTENSION * PCOMMON_DEVICE_EXTENSION
PVPB NTAPI ClassGetVpb(_In_ PDEVICE_OBJECT DeviceObject)
Definition: class.c:11473
PVOID ScreenStateNotificationHandle
Definition: class.c:124
BOOLEAN InterpretSenseInfoWithoutHistory(_In_ PDEVICE_OBJECT Fdo, _In_opt_ PIRP OriginalRequest, _In_ PSCSI_REQUEST_BLOCK Srb, UCHAR MajorFunctionCode, ULONG IoDeviceCode, ULONG PreviousRetryCount, _Out_ NTSTATUS *Status, _Out_opt_ _Deref_out_range_(0, MAXIMUM_RETRY_FOR_SINGLE_IO_IN_100NS_UNITS) LONGLONG *RetryIn100nsUnits)
Definition: class.c:12844
#define DBGGETADSENSECODESTR(_pSrb)
Definition: debug.h:29
#define DBGGETADSENSEQUALIFIERSTR(_pSrb)
Definition: debug.h:30
#define DBGGETSRBSTATUSSTR(_pSrb)
Definition: debug.h:27
#define DBGGETSENSECODESTR(_pSrb)
Definition: debug.h:28
VOID NTAPI ClassCompleteRequest(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, _In_ CCHAR PriorityBoost)
Definition: lock.c:401
VOID NTAPI ClassReleaseRemoveLock(_In_ PDEVICE_OBJECT DeviceObject, _In_opt_ PIRP Tag)
Definition: lock.c:251
struct _SCSI_REQUEST_BLOCK SCSI_REQUEST_BLOCK
#define SRB_STATUS_BUS_RESET
Definition: srb.h:353
#define SP_UNTAGGED
Definition: srb.h:233
#define SRB_FUNCTION_EXECUTE_SCSI
Definition: srb.h:315
#define SRB_FLAGS_NO_DATA_TRANSFER
Definition: srb.h:402
#define SRB_SIMPLE_TAG_REQUEST
Definition: srb.h:423
#define SRB_STATUS_AUTOSENSE_VALID
Definition: srb.h:387
struct _SCSI_REQUEST_BLOCK * PSCSI_REQUEST_BLOCK
#define SRB_FLAGS_DATA_IN
Definition: srb.h:400
#define SRB_FLAGS_NO_KEEP_AWAKE
Definition: srb.h:412
#define SRB_STATUS_ERROR
Definition: srb.h:344
#define SRB_FLAGS_DISABLE_SYNCH_TRANSFER
Definition: srb.h:397
#define SRB_STATUS(Status)
Definition: srb.h:389
#define SRB_STATUS_QUEUE_FROZEN
Definition: srb.h:386
#define SRB_FLAGS_NO_QUEUE_FREEZE
Definition: srb.h:404
#define SRB_STATUS_SUCCESS
Definition: srb.h:341
@ FdoExtension
Definition: precomp.h:48
#define _IRQL_requires_same_
Definition: driverspecs.h:232
#define _IRQL_requires_min_(irql)
Definition: driverspecs.h:231
#define _IRQL_requires_max_(irql)
Definition: driverspecs.h:230
#define _IRQL_requires_(irql)
Definition: driverspecs.h:229
#define InterlockedExchangePointer(Target, Value)
Definition: dshow.h:45
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
#define PASSIVE_LEVEL
Definition: env_spec_w32.h:693
#define KeWaitForSingleObject(pEvt, foo, a, b, c)
Definition: env_spec_w32.h:478
#define RtlCompareMemory(s1, s2, l)
Definition: env_spec_w32.h:465
#define KeInitializeEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:477
#define DO_VERIFY_VOLUME
Definition: env_spec_w32.h:393
#define KeSetEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:476
#define KeQuerySystemTime(t)
Definition: env_spec_w32.h:570
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
FORCEINLINE VOID EventDescCreate(_Out_ PEVENT_DESCRIPTOR EventDescriptor, _In_ USHORT Id, _In_ UCHAR Version, _In_ UCHAR Channel, _In_ UCHAR Level, _In_ USHORT Task, _In_ UCHAR Opcode, _In_ ULONGLONG Keyword)
Definition: evntprov.h:192
#define IoFreeMdl
Definition: fxmdl.h:89
#define IoAllocateMdl
Definition: fxmdl.h:88
PVOID dataBuffer
FxIrp * irp
struct _cl_event * event
Definition: glext.h:7739
GLuint buffer
Definition: glext.h:5915
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
GLintptr offset
Definition: glext.h:5920
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
_In_ GUID _In_ PVOID ValueData
Definition: hubbusif.h:312
#define OBJ_KERNEL_HANDLE
Definition: winternl.h:231
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
NTSYSAPI NTSTATUS WINAPI RtlQueryRegistryValues(ULONG, PCWSTR, PRTL_QUERY_REGISTRY_TABLE, PVOID, PVOID)
#define InterlockedCompareExchange
Definition: interlocked.h:104
VOID NTAPI IoQueueWorkItem(IN PIO_WORKITEM IoWorkItem, IN PIO_WORKITEM_ROUTINE WorkerRoutine, IN WORK_QUEUE_TYPE QueueType, IN PVOID Context)
Definition: iowork.c:40
VOID NTAPI IoFreeWorkItem(IN PIO_WORKITEM IoWorkItem)
Definition: iowork.c:64
PIO_WORKITEM NTAPI IoAllocateWorkItem(IN PDEVICE_OBJECT DeviceObject)
Definition: iowork.c:75
#define IoSetCompletionRoutine(_Irp, _CompletionRoutine, _Context, _InvokeOnSuccess, _InvokeOnError, _InvokeOnCancel)
Definition: irp.cpp:490
#define KeLeaveCriticalRegion()
Definition: ke_x.h:119
#define KeEnterCriticalRegion()
Definition: ke_x.h:88
#define REG_SZ
Definition: layer.c:22
if(dx< 0)
Definition: linetemp.h:194
#define PCHAR
Definition: match.c:90
VOID NTAPI MmBuildMdlForNonPagedPool(IN PMDL Mdl)
Definition: mdlsup.c:424
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
@ Enabled
Definition: mountmgr.h:159
#define _Function_class_(x)
Definition: ms_sal.h:2946
#define _In_reads_bytes_(size)
Definition: ms_sal.h:321
#define _Inout_
Definition: ms_sal.h:378
#define _In_z_
Definition: ms_sal.h:313
#define _In_
Definition: ms_sal.h:308
#define _In_reads_bytes_opt_(size)
Definition: ms_sal.h:322
#define _In_opt_
Definition: ms_sal.h:309
#define _Analysis_assume_(expr)
Definition: ms_sal.h:2901
#define KernelMode
Definition: asm.h:34
NTSYSAPI NTSTATUS NTAPI ZwClose(_In_ HANDLE Handle)
_In_ PCWSTR _Inout_ _At_ QueryTable EntryContext
Definition: rtlfuncs.h:4207
#define KEY_ALL_ACCESS
Definition: nt_native.h:1041
#define KEY_READ
Definition: nt_native.h:1023
NTSYSAPI NTSTATUS NTAPI RtlAnsiStringToUnicodeString(PUNICODE_STRING DestinationString, PANSI_STRING SourceString, BOOLEAN AllocateDestinationString)
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define REG_OPTION_NON_VOLATILE
Definition: nt_native.h:1057
#define RTL_QUERY_REGISTRY_REQUIRED
Definition: nt_native.h:132
#define RTL_QUERY_REGISTRY_DIRECT
Definition: nt_native.h:144
#define REG_MULTI_SZ
Definition: nt_native.h:1501
NTSYSAPI VOID NTAPI RtlFreeUnicodeString(PUNICODE_STRING UnicodeString)
#define REG_NONE
Definition: nt_native.h:1492
#define RTL_REGISTRY_OPTIONAL
Definition: nt_native.h:169
#define RTL_REGISTRY_HANDLE
Definition: nt_native.h:168
#define FILE_REMOVABLE_MEDIA
Definition: nt_native.h:807
#define RTL_SIZEOF_THROUGH_FIELD(type, field)
Definition: ntbasedef.h:672
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
@ BusTypeAtapi
Definition: ntddstor.h:440
* PSTORAGE_DEVICE_DESCRIPTOR
Definition: ntddstor.h:576
#define IOCTL_STORAGE_PREDICT_FAILURE
Definition: ntddstor.h:146
@ SynchronizationEvent
#define IO_WRN_FAILURE_PREDICTED
Definition: ntiologc.h:78
PDEVICE_OBJECT NTAPI IoGetAttachedDeviceReference(PDEVICE_OBJECT DeviceObject)
Definition: device.c:1406
PVOID NTAPI IoGetDriverObjectExtension(IN PDRIVER_OBJECT DriverObject, IN PVOID ClientIdentificationAddress)
Definition: driver.c:1904
VOID NTAPI IoWriteErrorLogEntry(IN PVOID ElEntry)
Definition: error.c:628
PVOID NTAPI IoAllocateErrorLogEntry(IN PVOID IoObject, IN UCHAR EntrySize)
Definition: error.c:528
PIRP NTAPI IoAllocateIrp(IN CCHAR StackSize, IN BOOLEAN ChargeQuota)
Definition: irp.c:615
VOID NTAPI IoReuseIrp(IN OUT PIRP Irp, IN NTSTATUS Status)
Definition: irp.c:1971
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
#define IoCallDriver
Definition: irp.c:1225
VOID NTAPI IoFreeIrp(IN PIRP Irp)
Definition: irp.c:1666
ULONG NTAPI KeQueryTimeIncrement(VOID)
Definition: clock.c:153
VOID NTAPI KeInitializeMutex(IN PKMUTEX Mutex, IN ULONG Level)
Definition: mutex.c:67
LONG NTAPI KeReleaseMutex(IN PKMUTEX Mutex, IN BOOLEAN Wait)
Definition: mutex.c:189
@ PowerDeviceD0
Definition: ntpoapi.h:49
#define STATUS_TIMEOUT
Definition: ntstatus.h:81
#define STATUS_DEVICE_PROTOCOL_ERROR
Definition: ntstatus.h:623
#define STATUS_MEDIA_CHANGED
Definition: ntstatus.h:207
#define STATUS_PENDING
Definition: ntstatus.h:82
#define STATUS_NOT_SUPPORTED
Definition: ntstatus.h:423
#define L(x)
Definition: ntvdm.h:50
long LONG
Definition: pedump.c:60
unsigned short USHORT
Definition: pedump.c:61
NTSTATUS NTAPI IoOpenDeviceRegistryKey(IN PDEVICE_OBJECT DeviceObject, IN ULONG DevInstKeyType, IN ACCESS_MASK DesiredAccess, OUT PHANDLE DevInstRegKey)
Definition: pnpmgr.c:1621
NTSTATUS NTAPI IoReportTargetDeviceChangeAsynchronous(IN PDEVICE_OBJECT PhysicalDeviceObject, IN PVOID NotificationStructure, IN PDEVICE_CHANGE_COMPLETE_CALLBACK Callback OPTIONAL, IN PVOID Context OPTIONAL)
Definition: pnpreport.c:498
NTKRNLVISTAAPI NTSTATUS NTAPI PoRegisterPowerSettingCallback(_In_opt_ PDEVICE_OBJECT DeviceObject, _In_ LPCGUID SettingGuid, _In_ PPOWER_SETTING_CALLBACK Callback, _In_opt_ PVOID Context, _Outptr_opt_ PVOID *Handle)
Definition: po.c:14
#define FILE_DEVICE_CD_ROM
Definition: winioctl.h:108
#define FILE_DEVICE_DISK
Definition: winioctl.h:113
#define IRP_MJ_DEVICE_CONTROL
Definition: rdpdr.c:52
#define IOCTL_SCSI_GET_ADDRESS
Definition: scsi_port.h:52
#define CLASS_SPECIAL_CAUSE_NOT_REPORTABLE_HACK
Definition: scsi_port.h:175
#define REG_DWORD
Definition: sdbapi.c:596
#define NOTIFICATION_DEVICE_BUSY_CLASS_EVENTS
Definition: scsi.h:48
#define NOTIFICATION_MEDIA_EVENT_MEDIA_CHANGE
Definition: scsi.h:97
UCHAR additionalSenseCode
Definition: scsi.h:4020
struct _NOTIFICATION_OPERATIONAL_STATUS * PNOTIFICATION_OPERATIONAL_STATUS
#define NOTIFICATION_MEDIA_STATUS_CLASS_MASK
Definition: scsi.h:37
struct _NOTIFICATION_EXTERNAL_STATUS * PNOTIFICATION_EXTERNAL_STATUS
#define NOTIFICATION_MEDIA_EVENT_NEW_MEDIA
Definition: scsi.h:95
#define NOTIFICATION_OPERATIONAL_OPCODE_FEATURE_CHANGE
Definition: scsi.h:59
#define NOTIFICATION_EXTERNAL_REQUEST_CLASS_MASK
Definition: scsi.h:36
#define NOTIFICATION_NO_CLASS_EVENTS
Definition: scsi.h:42
#define SCSI_SENSE_ERRORCODE_FIXED_CURRENT
Definition: scsi.h:623
#define SCSI_SENSE_OPTIONS_FIXED_FORMAT_IF_UNKNOWN_FORMAT_INDICATED
Definition: scsi.h:3839
#define NOTIFICATION_EXTERNAL_EVENT_BUTTON_DOWN
Definition: scsi.h:76
#define NOTIFICATION_OPERATIONAL_CHANGE_CLASS_MASK
Definition: scsi.h:34
struct _NOTIFICATION_EVENT_STATUS_HEADER * PNOTIFICATION_EVENT_STATUS_HEADER
struct _NOTIFICATION_MEDIA_STATUS * PNOTIFICATION_MEDIA_STATUS
#define NOTIFICATION_MEDIA_EVENT_EJECT_REQUEST
Definition: scsi.h:94
UCHAR senseKey
Definition: scsi.h:4019
#define NOTIFICATION_MEDIA_STATUS_CLASS_EVENTS
Definition: scsi.h:46
#define NOTIFICATION_DEVICE_BUSY_CLASS_MASK
Definition: scsi.h:39
struct _NOTIFICATION_BUSY_STATUS * PNOTIFICATION_BUSY_STATUS
#define NOTIFICATION_EXTERNAL_REQUEST_CLASS_EVENTS
Definition: scsi.h:45
#define NOTIFICATION_MEDIA_EVENT_MEDIA_REMOVAL
Definition: scsi.h:96
#define NOTIFICATION_OPERATIONAL_OPCODE_FEATURE_ADDED
Definition: scsi.h:60
#define SENSE_BUFFER_SIZE_EX
Definition: scsi.h:596
#define NOTIFICATION_OPERATIONAL_CHANGE_CLASS_EVENTS
Definition: scsi.h:43
ULONG dataLength
Definition: scsi.h:3751
BOOLEAN validSense
Definition: scsi.h:4018
#define NOTIFICATION_OPERATIONAL_EVENT_CHANGE_REQUESTED
Definition: scsi.h:51
#define SRB_TYPE_STORAGE_REQUEST_BLOCK
Definition: srb.h:664
#define SRB_FUNCTION_STORAGE_REQUEST_BLOCK
Definition: srb.h:108
#define STORAGE_ADDRESS_TYPE_BTL8
Definition: srb.h:666
* PSTORAGE_REQUEST_BLOCK
Definition: srb.h:661
@ SrbExDataTypeScsiCdb16
Definition: srb.h:459
struct SRB_ALIGN _STORAGE_REQUEST_BLOCK_HEADER * PSTORAGE_REQUEST_BLOCK_HEADER
int zero
Definition: sehframes.cpp:29
#define STATUS_MORE_PROCESSING_REQUIRED
Definition: shellext.h:68
#define STATUS_SUCCESS
Definition: shellext.h:65
FORCEINLINE VOID SrbSetScsiStatus(_In_ PVOID Srb, _In_ UCHAR ScsiStatus)
Definition: srbhelper.h:1056
FORCEINLINE VOID SrbSetSenseInfoBufferLength(_In_ PVOID Srb, _In_ UCHAR SenseInfoBufferLength)
Definition: srbhelper.h:675
FORCEINLINE VOID SrbSetSenseInfoBuffer(_In_ PVOID Srb, _In_opt_ PVOID SenseInfoBuffer)
Definition: srbhelper.h:657
FORCEINLINE VOID SrbSetCdbLength(_In_ PVOID Srb, _In_ UCHAR CdbLength)
Definition: srbhelper.h:1093
FORCEINLINE PVOID SrbGetSenseInfoBuffer(_In_ PVOID Srb)
Definition: srbhelper.h:619
FORCEINLINE UCHAR SrbGetSenseInfoBufferLength(_In_ PVOID Srb)
Definition: srbhelper.h:638
#define TRACE_LEVEL_WARNING
Definition: storswtr.h:28
#define TRACE_LEVEL_VERBOSE
Definition: storswtr.h:30
#define TRACE_LEVEL_ERROR
Definition: storswtr.h:27
#define TRACE_LEVEL_INFORMATION
Definition: storswtr.h:29
USHORT MaximumLength
Definition: env_spec_w32.h:377
CLASS_INIT_DATA InitData
Definition: classpnp.h:577
UNICODE_STRING RegistryPath
Definition: kbdclass.h:25
PCLASS_TICK ClassTick
Definition: classpnp.h:545
BOOLEAN TickTimerEnabled
Definition: classp.h:813
PEX_TIMER TickTimer
Definition: classp.h:676
BOOLEAN TimerInitialized
Definition: classp.h:752
LONGLONG CurrentNoWakeTolerance
Definition: classp.h:677
BOOLEAN LoggedTURFailureSinceLastIO
Definition: classp.h:753
PCLASS_DRIVER_EXTENSION DriverExtension
Definition: classpnp.h:600
LARGE_INTEGER SystemTime
Definition: ioevent.h:92
LONGLONG NoWakeTolerance
Definition: extypes.h:286
PDEVICE_OBJECT DeviceObject
Definition: classpnp.h:871
struct _FAILURE_PREDICTION_INFO * FailurePredictionInfo
Definition: classpnp.h:919
COMMON_DEVICE_EXTENSION CommonExtension
Definition: classpnp.h:873
PMEDIA_CHANGE_DETECTION_INFO MediaChangeDetectionInfo
Definition: classpnp.h:905