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