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(¶ms,
924*3088717bSVictor Perevertkin WDF_REQUEST_REUSE_NO_FLAGS,
925*3088717bSVictor Perevertkin STATUS_NOT_SUPPORTED);
926*3088717bSVictor Perevertkin
927*3088717bSVictor Perevertkin status = WdfRequestReuse(info->MediaChangeRequest, ¶ms);
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(¶meterKeyName, L"Parameters");
2446*3088717bSVictor Perevertkin
2447*3088717bSVictor Perevertkin status = WdfRegistryOpenKey(serviceKey,
2448*3088717bSVictor Perevertkin ¶meterKeyName,
2449*3088717bSVictor Perevertkin KEY_READ,
2450*3088717bSVictor Perevertkin WDF_NO_OBJECT_ATTRIBUTES,
2451*3088717bSVictor Perevertkin ¶metersKey);
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