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