ReactOS 0.4.15-dev-7674-gc0b4db1
autorun.c File Reference
#include "stddef.h"
#include "string.h"
#include "ntddk.h"
#include "ntddstor.h"
#include "cdrom.h"
#include "mmc.h"
#include "ioctl.h"
#include "ntstrsafe.h"
Include dependency graph for autorun.c:

Go to the source code of this file.

Macros

#define GESN_TIMEOUT_VALUE   (0x4)
 
#define GESN_BUFFER_SIZE   (0x8)
 
#define GESN_DEVICE_BUSY_LOWER_THRESHOLD_100_MS   (2)
 
#define MAXIMUM_IMMEDIATE_MCN_RETRIES   (0x20)
 
#define MCN_REG_SUBKEY_NAME   (L"MediaChangeNotification")
 
#define MCN_REG_AUTORUN_DISABLE_INSTANCE_NAME   (L"AlwaysDisableMCN")
 
#define MCN_REG_AUTORUN_ENABLE_INSTANCE_NAME   (L"AlwaysEnableMCN")
 

Functions

 _IRQL_requires_max_ (PASSIVE_LEVEL)
 
VOID DeviceInternalSetMediaChangeState (_In_ PCDROM_DEVICE_EXTENSION DeviceExtension, _In_ MEDIA_CHANGE_DETECTION_STATE NewState, _Inout_opt_ PMEDIA_CHANGE_DETECTION_STATE OldState)
 
VOID DeviceSetMediaChangeStateEx (_In_ PCDROM_DEVICE_EXTENSION DeviceExtension, _In_ MEDIA_CHANGE_DETECTION_STATE NewState, _Inout_opt_ PMEDIA_CHANGE_DETECTION_STATE OldState)
 
 _IRQL_requires_max_ (APC_LEVEL)
 
VOID NTAPI DeviceDisableGesn (_In_ WDFWORKITEM WorkItem)
 
NTSTATUS NTAPI DeviceMediaChangeRegistryCallBack (_In_z_ PWSTR ValueName, _In_ ULONG ValueType, _In_reads_bytes_opt_(ValueLength) PVOID ValueData, _In_ ULONG ValueLength, _In_opt_ PVOID Context, _In_opt_ PVOID EntryContext)
 
NTSTATUS NTAPI RequestMcnSyncIrpCompletion (_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, _In_reads_opt_(_Inexpressible_("varies")) PVOID Context)
 
VOID RequestSetupMcnSyncIrp (_In_ PCDROM_DEVICE_EXTENSION DeviceExtension)
 
VOID NTAPI DeviceMainTimerTickHandler (_In_ WDFTIMER Timer)
 

Variables

IO_COMPLETION_ROUTINE RequestMcnSyncIrpCompletion
 

Macro Definition Documentation

◆ GESN_BUFFER_SIZE

#define GESN_BUFFER_SIZE   (0x8)

Definition at line 40 of file autorun.c.

◆ GESN_DEVICE_BUSY_LOWER_THRESHOLD_100_MS

#define GESN_DEVICE_BUSY_LOWER_THRESHOLD_100_MS   (2)

Definition at line 41 of file autorun.c.

◆ GESN_TIMEOUT_VALUE

#define GESN_TIMEOUT_VALUE   (0x4)

Definition at line 39 of file autorun.c.

◆ MAXIMUM_IMMEDIATE_MCN_RETRIES

#define MAXIMUM_IMMEDIATE_MCN_RETRIES   (0x20)

Definition at line 43 of file autorun.c.

◆ MCN_REG_AUTORUN_DISABLE_INSTANCE_NAME

#define MCN_REG_AUTORUN_DISABLE_INSTANCE_NAME   (L"AlwaysDisableMCN")

Definition at line 45 of file autorun.c.

◆ MCN_REG_AUTORUN_ENABLE_INSTANCE_NAME

#define MCN_REG_AUTORUN_ENABLE_INSTANCE_NAME   (L"AlwaysEnableMCN")

Definition at line 46 of file autorun.c.

◆ MCN_REG_SUBKEY_NAME

#define MCN_REG_SUBKEY_NAME   (L"MediaChangeNotification")

Definition at line 44 of file autorun.c.

Function Documentation

◆ _IRQL_requires_max_() [1/2]

_IRQL_requires_max_ ( APC_LEVEL  )

Definition at line 812 of file autorun.c.

836{
837 PMEDIA_CHANGE_DETECTION_INFO info = DeviceExtension->MediaChangeDetectionInfo;
840
841 PAGED_CODE();
842
843 zero.QuadPart = 0;
844
845 if (info == NULL)
846 {
847 return;
848 }
849
850 status = KeWaitForMutexObject(&info->MediaChangeMutex,
851 Executive,
853 FALSE,
854 &zero);
855
856 if (status == STATUS_TIMEOUT)
857 {
858 // Someone else is in the process of setting the media state.
859 // That's totally okay, we'll send delayed notifications later.
860 return;
861 }
862
863 // If the last reported state and the last known state are different and
864 // MCN is enabled, generate a notification based on the last known state.
865 if ((info->LastKnownMediaDetectionState != info->LastReportedMediaDetectionState) &&
866 (info->MediaChangeDetectionDisableCount == 0))
867 {
868 DeviceInternalSetMediaChangeState(DeviceExtension, info->LastKnownMediaDetectionState, NULL);
869 }
870
871 KeReleaseMutex(&info->MediaChangeMutex, FALSE);
872
873 return;
874}
#define PAGED_CODE()
LONG NTSTATUS
Definition: precomp.h:26
VOID DeviceInternalSetMediaChangeState(_In_ PCDROM_DEVICE_EXTENSION DeviceExtension, _In_ MEDIA_CHANGE_DETECTION_STATE NewState, _Inout_opt_ PMEDIA_CHANGE_DETECTION_STATE OldState)
Definition: autorun.c:630
#define NULL
Definition: types.h:112
#define FALSE
Definition: types.h:117
#define KernelMode
Definition: asm.h:34
LONG NTAPI KeReleaseMutex(IN PKMUTEX Mutex, IN BOOLEAN Wait)
Definition: mutex.c:189
#define STATUS_TIMEOUT
Definition: ntstatus.h:81
int zero
Definition: sehframes.cpp:29
Definition: ps.c:97
#define KeWaitForMutexObject
Definition: kefuncs.h:543
@ Executive
Definition: ketypes.h:415

◆ _IRQL_requires_max_() [2/2]

_IRQL_requires_max_ ( PASSIVE_LEVEL  )

Definition at line 66 of file autorun.c.

146 :4152) // nonstandard extension, function/data pointer conversion in expression
147
148
151GesnDataInterpret(
152 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
154 _Out_ PBOOLEAN ResendImmediately
155 )
156/*++
157
158Routine Description:
159
160 This routine will interpret the data returned for a GESN command, and
161 (if appropriate) set the media change event, and broadcast the
162 appropriate events to user mode for applications who care.
163
164Arguments:
165
166 DeviceExtension - the device extension
167
168 Header - the resulting data from a GESN event.
169 requires at least EIGHT valid bytes (header == 4, data == 4)
170
171 ResendImmediately - whether or not to immediately resend the request.
172 this should be FALSE if there was no event, FALSE if the reported
173 event was of the DEVICE BUSY class, else true.
174
175Return Value:
176
177 STATUS_SUCCESS if successful, an error code otherwise
178
179Notes:
180
181 DataBuffer must be at least four bytes of valid data (header == 4 bytes),
182 and have at least eight bytes of allocated memory (all events == 4 bytes).
183
184 The call to StartNextPacket may occur before this routine is completed.
185 the operational change notifications are informational in nature, and
186 while useful, are not neccessary to ensure proper operation. For example,
187 if the device morphs to no longer supporting WRITE commands, all further
188 write commands will fail. There exists a small timing window wherein
189 IOCTL_IS_DISK_WRITABLE may be called and get an incorrect response. If
190 a device supports software write protect, it is expected that the
191 application can handle such a case.
192
193 NOTE: perhaps setting the updaterequired byte to one should be done here.
194 if so, it relies upon the setting of a 32-byte value to be an atomic
195 operation. unfortunately, there is no simple way to notify a class driver
196 which wants to know that the device behavior requires updating.
197
198 Not ready events may be sent every second. For example, if we were
199 to minimize the number of asynchronous notifications, an application may
200 register just after a large busy time was reported. This would then
201 prevent the application from knowing the device was busy until some
202 arbitrarily chosen timeout has occurred. Also, the GESN request would
203 have to still occur, since it checks for non-busy events (such as user
204 keybutton presses and media change events) as well. The specification
205 states that the lower-numered events get reported first, so busy events,
206 while repeating, will only be reported when all other events have been
207 cleared from the device.
208
209--*/
210{
212 PMEDIA_CHANGE_DETECTION_INFO info = DeviceExtension->MediaChangeDetectionInfo;
213 LONG dataLength = 0;
214 LONG requiredLength = 0;
215 BOOLEAN inHomePosition = FALSE;
216
217 PAGED_CODE();
218
219 // note: don't allocate anything in this routine so that we can
220 // always just 'return'.
221 *ResendImmediately = FALSE;
222
223 if (Header->NEA)
224 {
225 return status;
226 }
227 if (Header->NotificationClass == NOTIFICATION_NO_CLASS_EVENTS)
228 {
229 return status;
230 }
231
232 // HACKHACK - REF #0001
233 // This loop is only taken initially, due to the inability to reliably
234 // auto-detect drives that report events correctly at boot. When we
235 // detect this behavior during the normal course of running, we will
236 // disable the hack, allowing more efficient use of the system. This
237 // should occur "nearly" instantly, as the drive should have multiple
238 // events queue'd (ie. power, morphing, media).
239 if (info->Gesn.HackEventMask)
240 {
241 // all events use the low four bytes of zero to indicate
242 // that there was no change in status.
243 UCHAR thisEvent = Header->ClassEventData[0] & 0xf;
244 UCHAR lowestSetBit;
245 UCHAR thisEventBit = (1 << Header->NotificationClass);
246
247 if (!TEST_FLAG(info->Gesn.EventMask, thisEventBit))
248 {
249 // The drive is reporting an event that wasn't requested
251 }
252
253 // some bit magic here... this results in the lowest set bit only
254 lowestSetBit = info->Gesn.EventMask;
255 lowestSetBit &= (info->Gesn.EventMask - 1);
256 lowestSetBit ^= (info->Gesn.EventMask);
257
258 if (thisEventBit != lowestSetBit)
259 {
260 // HACKHACK - REF #0001
261 // the first time we ever see an event set that is not the lowest
262 // set bit in the request (iow, highest priority), we know that the
263 // hack is no longer required, as the device is ignoring "no change"
264 // events when a real event is waiting in the other requested queues.
265 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
266 "GESN::NONE: Compliant drive found, "
267 "removing GESN hack (%x, %x)\n",
268 thisEventBit, info->Gesn.EventMask));
269
270 info->Gesn.HackEventMask = FALSE;
271 }
272 else if (thisEvent == 0) // NOTIFICATION_*_EVENT_NO_CHANGE
273 {
274 // HACKHACK - REF #0001
275 // note: this hack prevents poorly implemented firmware from constantly
276 // returning "No Event". we do this by cycling through the
277 // supported list of events here.
278 SET_FLAG(info->Gesn.NoChangeEventMask, thisEventBit);
279 CLEAR_FLAG(info->Gesn.EventMask, thisEventBit);
280
281 // if we have cycled through all supported event types, then
282 // we need to reset the events we are asking about. else we
283 // want to resend this request immediately in case there was
284 // another event pending.
285 if (info->Gesn.EventMask == 0)
286 {
287 info->Gesn.EventMask = info->Gesn.NoChangeEventMask;
288 info->Gesn.NoChangeEventMask = 0;
289 }
290 else
291 {
292 *ResendImmediately = TRUE;
293 }
294 return status;
295 }
296
297 } // end if (info->Gesn.HackEventMask)
298
299 dataLength = (Header->EventDataLength[0] << 8) |
300 (Header->EventDataLength[1] & 0xff);
301 dataLength -= 2;
302 requiredLength = 4; // all events are four bytes
303
304 if (dataLength < requiredLength)
305 {
306 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN,
307 "error - GESN returned only %x bytes data for fdo %p\n",
308 dataLength, DeviceExtension->DeviceObject));
309
311 }
312
313 if (dataLength > requiredLength)
314 {
315 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN,
316 "error - GESN returned too many (%x) bytes data for fdo %p\n",
317 dataLength, DeviceExtension->DeviceObject));
318 }
319
320 if ((Header->ClassEventData[0] & 0xf) == 0)
321 {
322 // a zero event is a "no change event, so do not retry
323 return status;
324 }
325
326 // because a event other than "no change" occurred,
327 // we should immediately resend this request.
328 *ResendImmediately = TRUE;
329
330 switch (Header->NotificationClass)
331 {
332
334 {
336 (PNOTIFICATION_OPERATIONAL_STATUS)(Header->ClassEventData);
337 ULONG event;
338
340 {
341 break;
342 }
343
344 event = (opChangeInfo->Operation[0] << 8) |
345 (opChangeInfo->Operation[1] ) ;
346
347 // Workaround some hardware that is buggy but prevalent in the market
348 // This hardware has the property that it will report OpChange events repeatedly,
349 // causing us to retry immediately so quickly that we will eventually disable
350 // GESN to prevent an infinite loop.
351 // (only one valid OpChange event type now, only two ever defined)
352 if (info->MediaChangeRetryCount >= 4)
353 {
354 //
355 // HACKHACK - REF #0002
356 // Some drives incorrectly report OpChange/Change (001b/0001h) events
357 // continuously when the tray has been ejected. This causes this routine
358 // to set ResendImmediately to "TRUE", and that results in our cycling
359 // 32 times immediately resending. At that point, we give up detecting
360 // the infinite retry loop, and disable GESN on these drives. This
361 // prevents Media Eject Request (from eject button) from being reported.
362 // Thus, instead we should attempt to workaround this issue by detecting
363 // this behavior.
364 //
365
366 static UCHAR const OpChangeMask = 0x02;
367
368 // At least one device reports "temporarily busy" (which is useless) on eject
369 // At least one device reports "OpChange" repeatedly when re-inserting media
370 // All seem to work well using this workaround
371
372 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_MCN,
373 "GESN OpChange events are broken. Working around this problem in software (for WDFDEVICE %p)\n",
374 DeviceExtension->Device));
375
376 // OpChange is not the only bit set -- Media class is required....
377 NT_ASSERT(CountOfSetBitsUChar(info->Gesn.EventMask) != 1);
378
379 // Force the use of the hackhack (ref #0001) to workaround the
380 // issue noted this hackhack (ref #0002).
381 SET_FLAG(info->Gesn.NoChangeEventMask, OpChangeMask);
382 CLEAR_FLAG(info->Gesn.EventMask, OpChangeMask);
383 info->Gesn.HackEventMask = TRUE;
384
385 // don't request the opChange event again. use the method
386 // defined by hackhack (ref #0001) as the workaround.
387 if (info->Gesn.EventMask == 0)
388 {
389 info->Gesn.EventMask = info->Gesn.NoChangeEventMask;
390 info->Gesn.NoChangeEventMask = 0;
391 *ResendImmediately = FALSE;
392 }
393 else
394 {
395 *ResendImmediately = TRUE;
396 }
397
398 break;
399 }
400
401
404 {
405 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
406 "GESN says features added/changed for WDFDEVICE %p\n",
407 DeviceExtension->Device));
408
409 // don't notify that new media arrived, just set the
410 // DO_VERIFY to force a FS reload.
411
412 if (IsVolumeMounted(DeviceExtension->DeviceObject))
413 {
414 SET_FLAG(DeviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME);
415 }
416
417 // Call error handler with
418 // a "fake" media change error in case it needs to update
419 // internal structures as though a media change occurred.
420 {
421 SCSI_REQUEST_BLOCK srb = {0};
422 SENSE_DATA sense = {0};
423 NTSTATUS tempStatus;
424 BOOLEAN retry;
425
426 tempStatus = STATUS_MEDIA_CHANGED;
427 retry = FALSE;
428
429 srb.CdbLength = 6;
430 srb.Length = sizeof(SCSI_REQUEST_BLOCK);
432 srb.SenseInfoBuffer = &sense;
433 srb.SenseInfoBufferLength = sizeof(SENSE_DATA);
434
435 sense.AdditionalSenseLength = sizeof(SENSE_DATA) -
436 RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseLength);
437
440
441 if (DeviceExtension->DeviceAdditionalData.ErrorHandler)
442 {
443 DeviceExtension->DeviceAdditionalData.ErrorHandler(DeviceExtension,
444 &srb,
445 &tempStatus,
446 &retry);
447 }
448 } // end error handler
449
450 }
451 break;
452 }
453
455 {
456 PNOTIFICATION_EXTERNAL_STATUS externalInfo =
457 (PNOTIFICATION_EXTERNAL_STATUS)(Header->ClassEventData);
458 DEVICE_EVENT_EXTERNAL_REQUEST externalData = {0};
459
460 // unfortunately, due to time constraints, we will only notify
461 // about keys being pressed, and not released. this makes keys
462 // single-function, but simplifies the code significantly.
464 {
465 break;
466 }
467
468 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
469 "GESN::EXTERNAL: Event: %x Status %x Req %x\n",
470 externalInfo->ExternalEvent, externalInfo->ExternalStatus,
471 (externalInfo->Request[0] << 8) | externalInfo->Request[1]
472 ));
473
474 externalData.Version = 1;
475 externalData.DeviceClass = 0;
476 externalData.ButtonStatus = externalInfo->ExternalEvent;
477 externalData.Request = (externalInfo->Request[0] << 8) |
478 (externalInfo->Request[1] & 0xff);
479 KeQuerySystemTime(&(externalData.SystemTime));
481
482 DeviceSendNotification(DeviceExtension,
483 &GUID_IO_DEVICE_EXTERNAL_REQUEST,
485 &externalData);
486
487 return status;
488 }
489
491 {
493 (PNOTIFICATION_MEDIA_STATUS)(Header->ClassEventData);
494
497 {
498 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
499 "GESN::MEDIA ARRIVAL, Status %x\n",
500 mediaInfo->MediaStatus));
501
502 if (IsVolumeMounted(DeviceExtension->DeviceObject))
503 {
504 SET_FLAG(DeviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME);
505 }
506 DeviceSetMediaChangeStateEx(DeviceExtension,
508 NULL);
509
510 // If media is inserted into slot loading type, mark the device active
511 // to not power off.
512 if ((DeviceExtension->ZeroPowerODDInfo != NULL) &&
513 (DeviceExtension->ZeroPowerODDInfo->LoadingMechanism == LOADING_MECHANISM_CADDY) &&
514 (DeviceExtension->ZeroPowerODDInfo->Load == 0)) // Slot
515 {
516 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER,
517 "GesnDataInterpret: MediaArrival event detected, device marked as active\n"));
518
519 DeviceMarkActive(DeviceExtension, TRUE, FALSE);
520 }
521 }
523 {
524 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
525 "GESN::MEDIA REMOVAL, Status %x\n",
526 mediaInfo->MediaStatus));
527
528 DeviceSetMediaChangeStateEx(DeviceExtension,
530 NULL);
531
532 // If media is removed from slot loading type, start powering off the device
533 // if it is ZPODD capable.
534 if ((DeviceExtension->ZeroPowerODDInfo != NULL) &&
535 (DeviceExtension->ZeroPowerODDInfo->LoadingMechanism == LOADING_MECHANISM_CADDY) &&
536 (DeviceExtension->ZeroPowerODDInfo->Load == 0)) // Slot
537 {
538 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER,
539 "GesnDataInterpret: MediaRemoval event detected, device marked as idle\n"));
540
541 DeviceMarkActive(DeviceExtension, FALSE, FALSE);
542 }
543 }
545 {
546 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
547 "GESN::MEDIA EJECTION, Status %x\n",
548 mediaInfo->MediaStatus));
549
550 DeviceSendNotification(DeviceExtension,
551 &GUID_IO_MEDIA_EJECT_REQUEST,
552 0,
553 NULL);
554 }
555
556 break;
557 }
558
559 case NOTIFICATION_DEVICE_BUSY_CLASS_EVENTS: // lowest priority events...
560 {
562 (PNOTIFICATION_BUSY_STATUS)(Header->ClassEventData);
563 DEVICE_EVENT_BECOMING_READY busyData = {0};
564
565 // else we want to report the approximated time till it's ready.
566 busyData.Version = 1;
567 busyData.Reason = busyInfo->DeviceBusyStatus;
568 busyData.Estimated100msToReady = (busyInfo->Time[0] << 8) |
569 (busyInfo->Time[1] & 0xff);
570
571 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
572 "GESN::BUSY: Event: %x Status %x Time %x\n",
573 busyInfo->DeviceBusyEvent, busyInfo->DeviceBusyStatus,
574 busyData.Estimated100msToReady
575 ));
576
577 // Ignore the notification if the time is small
579 {
580 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
581 "GesnDataInterpret: media BECOMING_READY\n"));
582
583 DeviceSendNotification(DeviceExtension,
584 &GUID_IO_DEVICE_BECOMING_READY,
586 &busyData);
587 }
588
589 // If manual loading operation is observed for slot loading type, start powering off the device
590 // if it is ZPODD capable.
591 if ((DeviceExtension->ZeroPowerODDInfo != NULL) &&
592 (DeviceExtension->ZeroPowerODDInfo->LoadingMechanism == LOADING_MECHANISM_TRAY) &&
593 (DeviceExtension->ZeroPowerODDInfo->Load == 0) && // Drawer
596 {
597 inHomePosition = DeviceZPODDIsInHomePosition(DeviceExtension);
598
599 if (inHomePosition == FALSE)
600 {
601 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER,
602 "GesnDataInterpret: LoChange event detected, device marked as active\n"));
603
604 DeviceMarkActive(DeviceExtension, TRUE, FALSE);
605 }
606 else
607 {
608 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER,
609 "GesnDataInterpret: LoChange event detected, device marked as idle\n"));
610
611 DeviceMarkActive(DeviceExtension, FALSE, FALSE);
612 }
613 }
614
615 break;
616 }
617
618 default:
619 {
620 break;
621 }
622
623 } // end switch on notification class
624
625 return status;
626}
unsigned char BOOLEAN
VOID DeviceSetMediaChangeStateEx(_In_ PCDROM_DEVICE_EXTENSION DeviceExtension, _In_ MEDIA_CHANGE_DETECTION_STATE NewState, _Inout_opt_ PMEDIA_CHANGE_DETECTION_STATE OldState)
Definition: autorun.c:751
#define GESN_DEVICE_BUSY_LOWER_THRESHOLD_100_MS
Definition: autorun.c:41
FORCEINLINE BOOLEAN IsVolumeMounted(_In_ PDEVICE_OBJECT DeviceObject)
Definition: cdrom.h:1514
#define TEST_FLAG(Flags, Bit)
Definition: cdrom.h:1495
#define CLEAR_FLAG(Flags, Bit)
Definition: cdrom.h:1494
FORCEINLINE ULONG CountOfSetBitsUChar(UCHAR _X)
Definition: cdrom.h:1500
VOID DeviceSendNotification(_In_ PCDROM_DEVICE_EXTENSION DeviceExtension, _In_ const GUID *Guid, _In_ ULONG ExtraDataSize, _In_opt_ PVOID ExtraData)
Definition: common.c:799
#define SET_FLAG(Flags, Bit)
Definition: cdrom.h:1493
@ MediaPresent
Definition: cdromp.h:82
@ MediaNotPresent
Definition: cdromp.h:83
struct _SENSE_DATA SENSE_DATA
#define SCSI_SENSE_UNIT_ATTENTION
Definition: cdrw_hw.h:1193
#define SCSI_ADSENSE_MEDIUM_CHANGED
Definition: cdrw_hw.h:1288
Definition: Header.h:9
#define TRUE
Definition: types.h:120
struct _SCSI_REQUEST_BLOCK SCSI_REQUEST_BLOCK
#define SRB_STATUS_AUTOSENSE_VALID
Definition: srb.h:387
#define SRB_STATUS_ERROR
Definition: srb.h:344
#define _IRQL_requires_max_(irql)
Definition: driverspecs.h:230
#define DO_VERIFY_VOLUME
Definition: env_spec_w32.h:393
#define APC_LEVEL
Definition: env_spec_w32.h:695
#define KeQuerySystemTime(t)
Definition: env_spec_w32.h:570
struct _cl_event * event
Definition: glext.h:7739
#define _Out_
Definition: ms_sal.h:345
#define _In_
Definition: ms_sal.h:308
#define RTL_SIZEOF_THROUGH_FIELD(type, field)
Definition: ntbasedef.h:672
ULONG NTAPI KeQueryTimeIncrement(VOID)
Definition: clock.c:153
#define STATUS_DEVICE_PROTOCOL_ERROR
Definition: ntstatus.h:623
#define STATUS_MEDIA_CHANGED
Definition: ntstatus.h:207
long LONG
Definition: pedump.c:60
#define NOTIFICATION_DEVICE_BUSY_CLASS_EVENTS
Definition: scsi.h:48
#define NOTIFICATION_MEDIA_EVENT_MEDIA_CHANGE
Definition: scsi.h:97
struct _NOTIFICATION_OPERATIONAL_STATUS * PNOTIFICATION_OPERATIONAL_STATUS
struct _NOTIFICATION_EXTERNAL_STATUS * PNOTIFICATION_EXTERNAL_STATUS
#define NOTIFICATION_MEDIA_EVENT_NEW_MEDIA
Definition: scsi.h:95
#define NOTIFICATION_OPERATIONAL_OPCODE_FEATURE_CHANGE
Definition: scsi.h:59
#define NOTIFICATION_BUSY_EVENT_LO_CHANGE
Definition: scsi.h:116
#define NOTIFICATION_NO_CLASS_EVENTS
Definition: scsi.h:42
#define NOTIFICATION_EXTERNAL_EVENT_BUTTON_DOWN
Definition: scsi.h:76
#define LOADING_MECHANISM_CADDY
Definition: scsi.h:971
#define NOTIFICATION_BUSY_STATUS_NO_EVENT
Definition: scsi.h:118
struct _NOTIFICATION_MEDIA_STATUS * PNOTIFICATION_MEDIA_STATUS
#define NOTIFICATION_MEDIA_EVENT_EJECT_REQUEST
Definition: scsi.h:94
#define NOTIFICATION_MEDIA_STATUS_CLASS_EVENTS
Definition: scsi.h:46
struct _NOTIFICATION_BUSY_STATUS * PNOTIFICATION_BUSY_STATUS
#define NOTIFICATION_EXTERNAL_REQUEST_CLASS_EVENTS
Definition: scsi.h:45
#define NOTIFICATION_MEDIA_EVENT_MEDIA_REMOVAL
Definition: scsi.h:96
#define LOADING_MECHANISM_TRAY
Definition: scsi.h:972
#define NOTIFICATION_OPERATIONAL_OPCODE_FEATURE_ADDED
Definition: scsi.h:60
#define NOTIFICATION_OPERATIONAL_CHANGE_CLASS_EVENTS
Definition: scsi.h:43
ULONG dataLength
Definition: scsi.h:3751
#define NOTIFICATION_OPERATIONAL_EVENT_CHANGE_REQUESTED
Definition: scsi.h:51
#define STATUS_SUCCESS
Definition: shellext.h:65
#define TRACE_LEVEL_WARNING
Definition: storswtr.h:28
#define TRACE_LEVEL_ERROR
Definition: storswtr.h:27
#define TRACE_LEVEL_INFORMATION
Definition: storswtr.h:29
LARGE_INTEGER SystemTime
Definition: ioevent.h:92
UCHAR SenseInfoBufferLength
Definition: srb.h:259
UCHAR CdbLength
Definition: srb.h:258
PVOID SenseInfoBuffer
Definition: srb.h:264
USHORT Length
Definition: srb.h:249
UCHAR SrbStatus
Definition: srb.h:251
UCHAR AdditionalSenseLength
Definition: cdrw_hw.h:1173
UCHAR AdditionalSenseCode
Definition: cdrw_hw.h:1175
UCHAR SenseKey
Definition: cdrw_hw.h:1167
unsigned char * PBOOLEAN
Definition: typedefs.h:53
int64_t LONGLONG
Definition: typedefs.h:68
uint32_t ULONG
Definition: typedefs.h:59
LONGLONG QuadPart
Definition: typedefs.h:114
#define NT_ASSERT
Definition: rtlfuncs.h:3310
unsigned char UCHAR
Definition: xmlstorage.h:181

◆ DeviceDisableGesn()

VOID NTAPI DeviceDisableGesn ( _In_ WDFWORKITEM  WorkItem)

Definition at line 1019 of file autorun.c.

1036{
1037 WDFDEVICE device = WdfWorkItemGetParentObject(WorkItem);
1038 PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(device);
1039
1040 PAGED_CODE();
1041
1042 //
1043 // Set the hack flag in the registry
1044 //
1045 DeviceSetParameter(deviceExtension,
1049
1050 WdfObjectDelete(WorkItem);
1051
1052 return;
1053}
@ CdromDetectionUnsupported
Definition: cdromp.h:297
#define CLASSP_REG_MMC_DETECTION_VALUE_NAME
Definition: cdromp.h:123
#define CLASSP_REG_SUBKEY_NAME
Definition: cdromp.h:120
Definition: devices.h:37
_Must_inspect_result_ _In_ PWDF_WORKITEM_CONFIG _In_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFWORKITEM * WorkItem
Definition: wdfworkitem.h:115

◆ DeviceInternalSetMediaChangeState()

VOID DeviceInternalSetMediaChangeState ( _In_ PCDROM_DEVICE_EXTENSION  DeviceExtension,
_In_ MEDIA_CHANGE_DETECTION_STATE  NewState,
_Inout_opt_ PMEDIA_CHANGE_DETECTION_STATE  OldState 
)

Definition at line 630 of file autorun.c.

661{
662#if DBG
663 LPCSTR states[] = {"Unknown", "Present", "Not Present", "Unavailable"};
664#endif
665 MEDIA_CHANGE_DETECTION_STATE oldMediaState;
666 PMEDIA_CHANGE_DETECTION_INFO info = DeviceExtension->MediaChangeDetectionInfo;
668
669 if (!((NewState >= MediaUnknown) && (NewState <= MediaUnavailable)))
670 {
671 return;
672 }
673
674 if (info == NULL)
675 {
676 return;
677 }
678
679 oldMediaState = info->LastKnownMediaDetectionState;
680 if (OldState)
681 {
682 *OldState = oldMediaState;
683 }
684
685 info->LastKnownMediaDetectionState = NewState;
686
687 // Increment MediaChangeCount on transition to MediaPresent
688 if (NewState == MediaPresent && oldMediaState != NewState)
689 {
690 InterlockedIncrement((PLONG)&DeviceExtension->MediaChangeCount);
691 }
692
693 if (info->MediaChangeDetectionDisableCount != 0)
694 {
695#if DBG
696 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
697 "DeviceInternalSetMediaChangeState: MCN not enabled, state "
698 "changed from %s to %s\n",
699 states[oldMediaState], states[NewState]));
700#endif
701 return;
702 }
703#if DBG
704 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
705 "DeviceInternalSetMediaChangeState: State change from %s to %s\n",
706 states[oldMediaState], states[NewState]));
707#endif
708
709 if (info->LastReportedMediaDetectionState == info->LastKnownMediaDetectionState)
710 {
711 // Media is in the same state as we reported last time, no need to report again.
712 return;
713 }
714
715 // make the data useful -- it used to always be zero.
716 mcnContext.MediaChangeCount = DeviceExtension->MediaChangeCount;
717 mcnContext.NewState = NewState;
718
719 if (NewState == MediaPresent)
720 {
721 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
722 "DeviceInternalSetMediaChangeState: Reporting media ARRIVAL\n"));
723
724 DeviceSendNotification(DeviceExtension,
725 &GUID_IO_MEDIA_ARRIVAL,
727 &mcnContext);
728 }
729 else if ((NewState == MediaNotPresent) || (NewState == MediaUnavailable))
730 {
731 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
732 "DeviceInternalSetMediaChangeState: Reporting media REMOVAL\n"));
733 DeviceSendNotification(DeviceExtension,
734 &GUID_IO_MEDIA_REMOVAL,
736 &mcnContext);
737 }
738 else
739 {
740 // Don't notify of changed going to unknown.
741 return;
742 }
743
744 info->LastReportedMediaDetectionState = info->LastKnownMediaDetectionState;
745
746 return;
747} // end DeviceInternalSetMediaChangeState()
#define InterlockedIncrement
Definition: armddk.h:53
@ MediaUnavailable
Definition: cdromp.h:84
enum _MEDIA_CHANGE_DETECTION_STATE MEDIA_CHANGE_DETECTION_STATE
int32_t * PLONG
Definition: typedefs.h:58
@ MediaUnknown
Definition: udf_common.h:10
const char * LPCSTR
Definition: xmlstorage.h:183

Referenced by _IRQL_requires_max_(), and DeviceSetMediaChangeStateEx().

◆ DeviceMainTimerTickHandler()

VOID NTAPI DeviceMainTimerTickHandler ( _In_ WDFTIMER  Timer)

Definition at line 2820 of file autorun.c.

2838{
2839 PCDROM_DEVICE_EXTENSION deviceExtension = NULL;
2840 size_t dataLength = 0;
2841
2842 deviceExtension = WdfObjectGetTypedContext(WdfTimerGetParentObject(Timer), CDROM_DEVICE_EXTENSION);
2843
2844 (void) RequestHandleEventNotification(deviceExtension, NULL, NULL, &dataLength);
2845
2846 return;
2847} // end DeviceMainTimerTickHandler()
#define WdfObjectGetTypedContext(handle, type)
Definition: wdfobject.h:404

◆ DeviceMediaChangeRegistryCallBack()

NTSTATUS NTAPI DeviceMediaChangeRegistryCallBack ( _In_z_ PWSTR  ValueName,
_In_ ULONG  ValueType,
_In_reads_bytes_opt_(ValueLength) PVOID  ValueData,
_In_ ULONG  ValueLength,
_In_opt_ PVOID  Context,
_In_opt_ PVOID  EntryContext 
)

Definition at line 2058 of file autorun.c.

2090{
2091 PULONG valueFound;
2092 PUNICODE_STRING deviceString;
2093 PWSTR keyValue;
2094
2095 PAGED_CODE();
2096
2098
2099 if ((Context == NULL) || (EntryContext == NULL))
2100 {
2101 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN,
2102 "DeviceMediaChangeRegistryCallBack: NULL context should never be passed to registry call-back!\n"));
2103
2104 return STATUS_SUCCESS;
2105 }
2106
2107 // if we have already set the value to true, exit
2108 valueFound = EntryContext;
2109 if ((*valueFound) != 0)
2110 {
2111 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2112 "DeviceMediaChangeRegistryCallBack: already set to true\n"));
2113 return STATUS_SUCCESS;
2114 }
2115
2116 if (ValueLength == sizeof(WCHAR))
2117 {
2118 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_MCN,
2119 "DeviceMediaChangeRegistryCallBack: NULL string should never be passed to registry call-back!\n"));
2120 return STATUS_SUCCESS;
2121 }
2122
2123 // if the data is not a terminated string, exit
2124 if (ValueType != REG_SZ)
2125 {
2126 return STATUS_SUCCESS;
2127 }
2128
2129 deviceString = Context;
2130 keyValue = ValueData;
2131 ValueLength -= sizeof(WCHAR); // ignore the null character
2132
2133 // do not compare more memory than is in deviceString
2134 if (ValueLength > deviceString->Length)
2135 {
2136 ValueLength = deviceString->Length;
2137 }
2138
2139 if (keyValue == NULL)
2140 {
2141 return STATUS_SUCCESS;
2142 }
2143
2144 // if the strings match, disable autorun
2145 if (RtlCompareMemory(deviceString->Buffer, keyValue, ValueLength) == ValueLength)
2146 {
2147 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_MCN, "DeviceMediaChangeRegistryCallBack: Match found\n"));
2148 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_MCN, "DeviceMediaChangeRegistryCallBack: DeviceString at %p\n",
2149 deviceString->Buffer));
2150 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_MCN,
2151 "DeviceMediaChangeRegistryCallBack: KeyValue at %p\n",
2152 keyValue));
2153 (*valueFound) = TRUE;
2154 }
2155
2156 return STATUS_SUCCESS;
2157} // end DeviceMediaChangeRegistryCallBack()
#define RtlCompareMemory(s1, s2, l)
Definition: env_spec_w32.h:465
_In_ GUID _In_ PVOID ValueData
Definition: hubbusif.h:312
#define REG_SZ
Definition: layer.c:22
_In_ PCWSTR _Inout_ _At_ QueryTable EntryContext
Definition: rtlfuncs.h:4207
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
#define TRACE_LEVEL_VERBOSE
Definition: storswtr.h:30
uint16_t * PWSTR
Definition: typedefs.h:56
uint32_t * PULONG
Definition: typedefs.h:59
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _In_ ULONG _Out_opt_ PULONG _Out_opt_ PULONG ValueType
Definition: wdfregistry.h:282
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING ValueName
Definition: wdfregistry.h:243
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _In_ ULONG ValueLength
Definition: wdfregistry.h:275
__wchar_t WCHAR
Definition: xmlstorage.h:180

◆ DeviceSetMediaChangeStateEx()

VOID DeviceSetMediaChangeStateEx ( _In_ PCDROM_DEVICE_EXTENSION  DeviceExtension,
_In_ MEDIA_CHANGE_DETECTION_STATE  NewState,
_Inout_opt_ PMEDIA_CHANGE_DETECTION_STATE  OldState 
)

Definition at line 751 of file autorun.c.

778{
779 PMEDIA_CHANGE_DETECTION_INFO info = DeviceExtension->MediaChangeDetectionInfo;
782
783 // timeout value must be 0, as this function can be called at DISPATCH_LEVEL.
784 zero.QuadPart = 0;
785
786 if (info == NULL)
787 {
788 return;
789 }
790
791 status = KeWaitForMutexObject(&info->MediaChangeMutex,
792 Executive,
794 FALSE,
795 &zero);
796
797 if (status == STATUS_TIMEOUT)
798 {
799 // Someone else is in the process of setting the media state.
800 return;
801 }
802
803 // Change the media present state and signal an event, if applicable
804 DeviceInternalSetMediaChangeState(DeviceExtension, NewState, OldState);
805
806 KeReleaseMutex(&info->MediaChangeMutex, FALSE);
807
808 return;
809} // end DeviceSetMediaChangeStateEx()

Referenced by DeviceEvtSelfManagedIoInit(), and SenseInfoInterpretByAdditionalSenseCode().

◆ RequestMcnSyncIrpCompletion()

NTSTATUS NTAPI RequestMcnSyncIrpCompletion ( _In_ PDEVICE_OBJECT  DeviceObject,
_In_ PIRP  Irp,
_In_reads_opt_(_Inexpressible_("varies")) PVOID  Context 
)

Definition at line 2695 of file autorun.c.

2719{
2720 PCDROM_DEVICE_EXTENSION DeviceExtension = NULL;
2722
2723 if (Context == NULL)
2724 {
2725 // this will never happen, but code must be there to prevent OACR warnings.
2727 }
2728
2729 DeviceExtension = (PCDROM_DEVICE_EXTENSION) Context;
2730 info = DeviceExtension->MediaChangeDetectionInfo;
2731
2732#ifndef DEBUG
2734#endif
2736
2737 NT_ASSERT(Irp == info->MediaChangeSyncIrp);
2738
2739 IoReuseIrp(info->MediaChangeSyncIrp, STATUS_NOT_SUPPORTED);
2740
2741 // reset the value to let timer routine be able to send the next request.
2742 InterlockedCompareExchange((PLONG)&(info->MediaChangeRequestInUse), 0, 1);
2743
2745}
struct _CDROM_DEVICE_EXTENSION * PCDROM_DEVICE_EXTENSION
Definition: cdrom.h:218
_In_ PIRP Irp
Definition: csq.h:116
#define InterlockedCompareExchange
Definition: interlocked.h:104
VOID NTAPI IoReuseIrp(IN OUT PIRP Irp, IN NTSTATUS Status)
Definition: irp.c:1971
#define STATUS_NOT_SUPPORTED
Definition: ntstatus.h:423
#define STATUS_MORE_PROCESSING_REQUIRED
Definition: shellext.h:68
PMEDIA_CHANGE_DETECTION_INFO MediaChangeDetectionInfo
Definition: cdrom.h:563
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2055

◆ RequestSetupMcnSyncIrp()

VOID RequestSetupMcnSyncIrp ( _In_ PCDROM_DEVICE_EXTENSION  DeviceExtension)

Definition at line 2749 of file autorun.c.

2766{
2767 PIRP irp = NULL;
2768 PIO_STACK_LOCATION irpStack = NULL;
2769 PIO_STACK_LOCATION nextIrpStack = NULL;
2770
2771 irp = DeviceExtension->MediaChangeDetectionInfo->MediaChangeSyncIrp;
2772 NT_ASSERT(irp != NULL);
2773
2774 //
2775 // For the driver that creates an IRP, there is no 'current' stack location.
2776 // Step down one IRP stack location so that the extra top one
2777 // becomes our 'current' one.
2778 //
2780
2781 /*
2782 * Cache our device object in the extra top IRP stack location
2783 * so we have it in our completion routine.
2784 */
2786 irpStack->DeviceObject = DeviceExtension->DeviceObject;
2787
2788 //
2789 // If the irp is sent down when the volume needs to be
2790 // verified, CdRomUpdateGeometryCompletion won't complete
2791 // it since it's not associated with a thread. Marking
2792 // it to override the verify causes it always be sent
2793 // to the port driver
2794 //
2795 nextIrpStack = IoGetNextIrpStackLocation(irp);
2796
2798
2799 nextIrpStack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
2800 // pick up this IOCTL code as it's not normaly seen for CD/DVD drive and does not require input.
2801 // set other fields to make this IOCTL recognizable by CDROM.SYS
2802 nextIrpStack->Parameters.Others.Argument1 = RequestSetupMcnSyncIrp;
2803 nextIrpStack->Parameters.Others.Argument2 = RequestSetupMcnSyncIrp;
2804 nextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_MCN_SYNC_FAKE_IOCTL; //Argument3.
2805 nextIrpStack->Parameters.Others.Argument4 = RequestSetupMcnSyncIrp;
2806
2809 DeviceExtension,
2810 TRUE,
2811 TRUE,
2812 TRUE);
2813
2814 return;
2815}
IO_COMPLETION_ROUTINE RequestMcnSyncIrpCompletion
Definition: autorun.c:2691
VOID RequestSetupMcnSyncIrp(_In_ PCDROM_DEVICE_EXTENSION DeviceExtension)
Definition: autorun.c:2749
#define IOCTL_MCN_SYNC_FAKE_IOCTL
Definition: cdrom.h:181
FxIrp * irp
#define IoSetCompletionRoutine(_Irp, _CompletionRoutine, _Context, _InvokeOnSuccess, _InvokeOnError, _InvokeOnCancel)
Definition: irp.cpp:490
#define IRP_MJ_DEVICE_CONTROL
Definition: rdpdr.c:52
PDEVICE_OBJECT DeviceObject
Definition: iotypes.h:3223
struct _NAMED_PIPE_CREATE_PARAMETERS * Parameters
Definition: iotypes.h:3128
__drv_aliasesMem FORCEINLINE PIO_STACK_LOCATION IoGetNextIrpStackLocation(_In_ PIRP Irp)
Definition: iofuncs.h:2695
FORCEINLINE VOID IoSetNextIrpStackLocation(_Inout_ PIRP Irp)
Definition: iofuncs.h:2680
__drv_aliasesMem FORCEINLINE PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(_In_ PIRP Irp)
Definition: iofuncs.h:2793
#define SL_OVERRIDE_VERIFY_VOLUME
Definition: iotypes.h:1823

Referenced by RequestDispatchSpecialIoctls(), and RequestSetupMcnSyncIrp().

Variable Documentation

◆ RequestMcnSyncIrpCompletion

IO_COMPLETION_ROUTINE RequestMcnSyncIrpCompletion

Definition at line 2691 of file autorun.c.

Referenced by RequestSetupMcnSyncIrp().