xref: /reactos/drivers/storage/class/cdrom/cdrom.c (revision 3088717b)
1 /*--
2 
3 Copyright (C) Microsoft Corporation. All rights reserved.
4 
5 Module Name:
6 
7     cdrom.c
8 
9 Abstract:
10 
11     The CDROM class driver tranlates IRPs to SRBs with embedded CDBs
12     and sends them to its devices through the port driver.
13 
14 Environment:
15 
16     kernel mode only
17 
18 Notes:
19 
20 
21 Revision History:
22 
23 --*/
24 
25 // this definition is used to link _StorDebugPrint() function.
26 #define DEBUG_MAIN_SOURCE   1
27 
28 
29 #include "ntddk.h"
30 #include "ntstrsafe.h"
31 
32 #include "ntddstor.h"
33 #include "ntddtape.h"
34 #include "wdfcore.h"
35 #include "devpkey.h"
36 
37 #include "cdrom.h"
38 #include "ioctl.h"
39 #include "mmc.h"
40 #include "scratch.h"
41 
42 
43 #ifdef DEBUG_USE_WPP
44 #include "cdrom.tmh"
45 #endif
46 
47 BOOLEAN
48 BootEnvironmentIsWinPE(
49     VOID
50     );
51 
52 #ifdef ALLOC_PRAGMA
53 
54 #pragma alloc_text(INIT, DriverEntry)
55 #pragma alloc_text(INIT, BootEnvironmentIsWinPE)
56 
57 #pragma alloc_text(PAGE, DriverEvtCleanup)
58 #pragma alloc_text(PAGE, DriverEvtDeviceAdd)
59 #pragma alloc_text(PAGE, DeviceEvtCleanup)
60 #pragma alloc_text(PAGE, DeviceEvtSelfManagedIoCleanup)
61 #pragma alloc_text(PAGE, DeviceEvtD0Exit)
62 #pragma alloc_text(PAGE, CreateQueueEvtIoDefault)
63 #pragma alloc_text(PAGE, DeviceEvtFileClose)
64 #pragma alloc_text(PAGE, DeviceCleanupProtectedLocks)
65 #pragma alloc_text(PAGE, DeviceCleanupDisableMcn)
66 #pragma alloc_text(PAGE, RequestProcessSerializedIoctl)
67 #pragma alloc_text(PAGE, ReadWriteWorkItemRoutine)
68 #pragma alloc_text(PAGE, IoctlWorkItemRoutine)
69 #pragma alloc_text(PAGE, DeviceEvtSurpriseRemoval)
70 
71 #endif
72 
73 NTSTATUS
74 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DriverEntry(_In_ PDRIVER_OBJECT DriverObject,_In_ PUNICODE_STRING RegistryPath)75 DriverEntry(
76     _In_ PDRIVER_OBJECT  DriverObject,
77     _In_ PUNICODE_STRING RegistryPath
78     )
79 /*++
80 
81 Routine Description:
82 
83     Installable driver initialization entry point.
84     This entry point is called directly by the I/O system.
85 
86 Arguments:
87 
88     DriverObject - pointer to the driver object
89 
90     RegistryPath - pointer to a unicode string representing the path,
91                    to driver-specific key in the registry.
92 
93 Return Value:
94 
95     STATUS_SUCCESS if successful,
96     STATUS_UNSUCCESSFUL otherwise.
97 
98 --*/
99 {
100     NTSTATUS                status;
101     WDF_DRIVER_CONFIG       config;
102     WDF_OBJECT_ATTRIBUTES   attributes;
103     WDFDRIVER               driverObject = NULL;
104 
105     PAGED_CODE();
106 
107     // Initialize WPP Tracing
108     WPP_INIT_TRACING(DriverObject, RegistryPath);
109 
110     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
111                 "CDROM.SYS DriverObject %p loading\n",
112                 DriverObject));
113 
114     // Register DeviceAdd and DriverEvtCleanup callback.
115     // WPP_CLEANUP will be called in DriverEvtCleanup
116     WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CDROM_DRIVER_EXTENSION);
117     attributes.EvtCleanupCallback = DriverEvtCleanup;
118 
119     WDF_DRIVER_CONFIG_INIT(&config, DriverEvtDeviceAdd);
120 
121     status = WdfDriverCreate(DriverObject,
122                              RegistryPath,
123                              &attributes,
124                              &config,
125                              &driverObject);
126 
127     if (!NT_SUCCESS(status))
128     {
129         TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_INIT,
130                     "WdfDriverCreate failed. %x\n",
131                     status));
132 
133         // Cleanup tracing here because DriverUnload will not be called
134         // as we have failed to create WDFDRIVER object itself.
135         WPP_CLEANUP(DriverObject);
136 
137     }
138     else
139     {
140         PCDROM_DRIVER_EXTENSION driverExtension = DriverGetExtension(driverObject);
141 
142         // Copy the registry path into the driver extension so we can use it later
143         driverExtension->Version = 0x01;
144         driverExtension->DriverObject = DriverObject;
145 
146         if (BootEnvironmentIsWinPE()) {
147 
148             SET_FLAG(driverExtension->Flags, CDROM_FLAG_WINPE_MODE);
149         }
150 
151     }
152 
153     return status;
154 }
155 
156 
157 BOOLEAN
BootEnvironmentIsWinPE(VOID)158 BootEnvironmentIsWinPE(
159     VOID
160     )
161 /*++
162 
163 Routine Description:
164 
165     This routine determines if the boot enviroment is WinPE
166 
167 Arguments:
168 
169     None
170 
171 Return Value:
172 
173     BOOLEAN - TRUE if the environment is WinPE; FALSE otherwise
174 
175 --*/
176 {
177     NTSTATUS    status;
178     WDFKEY      registryKey = NULL;
179 
180     DECLARE_CONST_UNICODE_STRING(registryKeyName, WINPE_REG_KEY_NAME);
181 
182     PAGED_CODE();
183 
184     status = WdfRegistryOpenKey(NULL,
185                                 &registryKeyName,
186                                 KEY_READ,
187                                 WDF_NO_OBJECT_ATTRIBUTES,
188                                 &registryKey);
189 
190     if (!NT_SUCCESS(status))
191     {
192         return FALSE;
193     }
194 
195     WdfRegistryClose(registryKey);
196     return TRUE;
197 } // end BootEnvironmentIsWinPE()
198 
199 
200 VOID
201 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DriverEvtCleanup(_In_ WDFOBJECT Driver)202 DriverEvtCleanup(
203     _In_ WDFOBJECT Driver
204     )
205 /*++
206 Routine Description:
207 
208     Free all the resources allocated in DriverEntry.
209 
210 Arguments:
211 
212     Driver - handle to a WDF Driver object.
213 
214 Return Value:
215 
216     VOID.
217 
218 --*/
219 {
220     WDFDRIVER driver = (WDFDRIVER)Driver;
221 
222     PAGED_CODE ();
223 
224     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
225                 "CDROM.SYS DriverObject %p cleanup. Will be unloaded soon\n",
226                 driver));
227 
228     // Stop WPP Tracing
229     WPP_CLEANUP( WdfDriverWdmGetDriverObject(driver) );
230 
231 
232     return;
233 }
234 
235 
236 NTSTATUS
237 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DriverEvtDeviceAdd(_In_ WDFDRIVER Driver,_Inout_ PWDFDEVICE_INIT DeviceInit)238 DriverEvtDeviceAdd(
239     _In_    WDFDRIVER        Driver,
240     _Inout_ PWDFDEVICE_INIT  DeviceInit
241     )
242 /*++
243 
244 Routine Description:
245 
246     EvtDeviceAdd is called by the framework in response to AddDevice
247     call from the PnP manager.
248 
249 
250 Arguments:
251 
252     Driver - Handle to a framework driver object created in DriverEntry
253 
254     DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure.
255 
256 Return Value:
257 
258     NTSTATUS
259 
260 --*/
261 {
262     NTSTATUS                        status = STATUS_SUCCESS;
263     PCDROM_DRIVER_EXTENSION         driverExtension = NULL;
264     WDFDEVICE                       device = NULL;
265     PCDROM_DEVICE_EXTENSION         deviceExtension = NULL;
266     BOOLEAN                         deviceClaimed = FALSE;
267 
268     WDF_OBJECT_ATTRIBUTES           attributes;
269     WDF_FILEOBJECT_CONFIG           fileObjectConfig;
270     WDF_IO_TARGET_OPEN_PARAMS       ioTargetOpenParams;
271     WDF_IO_QUEUE_CONFIG             queueConfig;
272     WDF_PNPPOWER_EVENT_CALLBACKS    pnpPowerCallbacks;
273     WDF_REMOVE_LOCK_OPTIONS         removeLockOptions;
274     PWCHAR                          wideDeviceName = NULL;
275     UNICODE_STRING                  unicodeDeviceName;
276     PDEVICE_OBJECT                  lowerPdo = NULL;
277     ULONG                           deviceNumber = 0;
278     ULONG                           devicePropertySessionId = INVALID_SESSION;
279     ULONG                           devicePropertySize = 0;
280     DEVPROPTYPE                     devicePropertyType = DEVPROP_TYPE_EMPTY;
281 
282     PAGED_CODE();
283 
284     driverExtension = DriverGetExtension(Driver);
285 
286     // 0. Initialize the objects that we're going to use
287     RtlInitUnicodeString(&unicodeDeviceName, NULL);
288 
289     // 1. Register PnP&Power callbacks for any we are interested in.
290     // If a callback isn't set, Framework will take the default action by itself.
291     {
292         // Zero out the PnpPowerCallbacks structure.
293         WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);
294 
295         // Use this callback to init resources that are used by the device and only needs to be called once.
296         pnpPowerCallbacks.EvtDeviceSelfManagedIoInit = DeviceEvtSelfManagedIoInit;
297 
298         // Use this callback to prepare device for coming back from a lower power mode to D0.
299         pnpPowerCallbacks.EvtDeviceD0Entry = DeviceEvtD0Entry;
300 
301         // Use this callback to prepare device for entering into a lower power mode.
302         pnpPowerCallbacks.EvtDeviceD0Exit = DeviceEvtD0Exit;
303 
304         // Use this callback to free any resources used by device and will be called when the device is
305         // powered down.
306         pnpPowerCallbacks.EvtDeviceSelfManagedIoCleanup = DeviceEvtSelfManagedIoCleanup;
307 
308         pnpPowerCallbacks.EvtDeviceSurpriseRemoval = DeviceEvtSurpriseRemoval;
309 
310         // Register the PnP and power callbacks.
311         WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks);
312     }
313 
314     // 2. Register the EvtIoInCallerContext to deal with IOCTLs that need to stay in original context.
315     WdfDeviceInitSetIoInCallerContextCallback(DeviceInit,
316                                               DeviceEvtIoInCallerContext);
317 
318     // 3. Register PreprocessCallback for IRP_MJ_POWER, IRP_MJ_FLUSH_BUFFERS and IRP_MJ_SHUTDOWN
319     {
320         UCHAR minorFunctions[1];
321 
322         minorFunctions[0] = IRP_MN_SET_POWER;
323 
324         status = WdfDeviceInitAssignWdmIrpPreprocessCallback(DeviceInit,
325                                                              RequestProcessSetPower,
326                                                              IRP_MJ_POWER,
327                                                              minorFunctions,
328                                                              RTL_NUMBER_OF(minorFunctions));
329         if (!NT_SUCCESS(status))
330         {
331             TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP,
332                         "DriverEvtDeviceAdd: Assign IrpPreprocessCallback for IRP_MJ_POWER failed, "
333                         "status: 0x%X\n", status));
334 
335             goto Exit;
336         }
337 
338         status = WdfDeviceInitAssignWdmIrpPreprocessCallback(DeviceInit,
339                                                              RequestProcessShutdownFlush,
340                                                              IRP_MJ_FLUSH_BUFFERS,
341                                                              NULL,
342                                                              0);
343         if (!NT_SUCCESS(status))
344         {
345             TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP,
346                         "DriverEvtDeviceAdd: Assign IrpPreprocessCallback for IRP_MJ_FLUSH_BUFFERS failed, "
347                         "status: 0x%X\n", status));
348 
349             goto Exit;
350         }
351 
352         status = WdfDeviceInitAssignWdmIrpPreprocessCallback(DeviceInit,
353                                                              RequestProcessShutdownFlush,
354                                                              IRP_MJ_SHUTDOWN,
355                                                              NULL,
356                                                              0);
357         if (!NT_SUCCESS(status))
358         {
359             TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP,
360                         "DriverEvtDeviceAdd: Assign IrpPreprocessCallback for IRP_MJ_SHUTDOWN failed, "
361                         "status: 0x%X\n", status));
362 
363             goto Exit;
364         }
365     }
366 
367     // 4. Set attributes to create Request Context area.
368     {
369         //Reuse this structure.
370         WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes,
371                                                 CDROM_REQUEST_CONTEXT);
372         attributes.EvtCleanupCallback = RequestEvtCleanup;
373 
374         WdfDeviceInitSetRequestAttributes(DeviceInit,
375                                           &attributes);
376     }
377 
378     // 5. Register FileObject related callbacks
379     {
380         // Add FILE_OBJECT_EXTENSION as the context to the file object.
381         WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, FILE_OBJECT_CONTEXT);
382 
383         // Set Entry points for Create and Close..
384 
385         // The framework doesn't sync the file create requests with pnp/power
386         // state. Re-direct all the file create requests to a dedicated
387         // queue, which will be purged manually during removal.
388         WDF_FILEOBJECT_CONFIG_INIT(&fileObjectConfig,
389                                    NULL, //CreateQueueEvtIoDefault,
390                                    DeviceEvtFileClose,
391                                    WDF_NO_EVENT_CALLBACK); // No callback for Cleanup
392 
393         fileObjectConfig.FileObjectClass = WdfFileObjectWdfCannotUseFsContexts;
394 
395         // Since we are registering file events and fowarding create request
396         // ourself, we must also set AutoForwardCleanupClose so that cleanup
397         // and close can also get forwarded.
398         fileObjectConfig.AutoForwardCleanupClose = WdfTrue;
399         attributes.SynchronizationScope = WdfSynchronizationScopeNone;
400         attributes.ExecutionLevel = WdfExecutionLevelPassive;
401 
402         // Indicate that file object is optional.
403         fileObjectConfig.FileObjectClass |= WdfFileObjectCanBeOptional;
404 
405         WdfDeviceInitSetFileObjectConfig(DeviceInit,
406                                          &fileObjectConfig,
407                                          &attributes);
408     }
409 
410     // 6. Initialize device-wide attributes
411     {
412         // Declare ourselves as NOT owning power policy.
413         // The power policy owner in storage stack is port driver.
414         WdfDeviceInitSetPowerPolicyOwnership(DeviceInit, FALSE);
415 
416         // Set other DeviceInit attributes.
417         WdfDeviceInitSetExclusive(DeviceInit, FALSE);
418         WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_CD_ROM);
419         WdfDeviceInitSetCharacteristics(DeviceInit, FILE_REMOVABLE_MEDIA, FALSE);
420         WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoDirect);
421         WdfDeviceInitSetPowerPageable(DeviceInit);
422 
423         // We require the framework to acquire a remove lock before delivering all IRP types
424         WDF_REMOVE_LOCK_OPTIONS_INIT(&removeLockOptions,
425                                      WDF_REMOVE_LOCK_OPTION_ACQUIRE_FOR_IO);
426 
427         WdfDeviceInitSetRemoveLockOptions(DeviceInit, &removeLockOptions);
428 
429         // save the PDO for later reference
430         lowerPdo = WdfFdoInitWdmGetPhysicalDevice(DeviceInit);
431 
432         WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes,
433                                                 CDROM_DEVICE_EXTENSION);
434 
435         // We have a parallel queue, so WdfSynchronizationScopeNone is our only choice.
436         attributes.SynchronizationScope = WdfSynchronizationScopeNone;
437         attributes.ExecutionLevel = WdfExecutionLevelDispatch;
438 
439         // Provide a cleanup callback which will release memory allocated with ExAllocatePool*
440         attributes.EvtCleanupCallback = DeviceEvtCleanup;
441     }
442 
443     // 7. Now, the device can be created.
444     {
445         wideDeviceName = ExAllocatePoolWithTag(NonPagedPoolNx,
446                                                64 * sizeof(WCHAR),
447                                                CDROM_TAG_STRINGS);
448 
449         if (wideDeviceName == NULL)
450         {
451             status = STATUS_INSUFFICIENT_RESOURCES;
452             goto Exit;
453         }
454 
455         // Find the lowest device number currently available.
456         do {
457             status = RtlStringCchPrintfW((NTSTRSAFE_PWSTR)wideDeviceName,
458                                          64,
459                                          L"\\Device\\CdRom%d",
460                                          deviceNumber);
461 
462             if (!NT_SUCCESS(status)) {
463                 TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP,
464                             "DriverEvtDeviceAdd: Format device name failed with error: 0x%X\n", status));
465 
466                 goto Exit;
467             }
468 
469             RtlInitUnicodeString(&unicodeDeviceName, wideDeviceName);
470 
471             status = WdfDeviceInitAssignName(DeviceInit, &unicodeDeviceName);
472             if (!NT_SUCCESS(status))
473             {
474                 TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP,
475                             "DriverEvtDeviceAdd: WdfDeviceInitAssignName() failed with error: 0x%X\n", status));
476 
477                 goto Exit;
478             }
479 
480             status = WdfDeviceCreate(&DeviceInit, &attributes, &device);
481 
482             deviceNumber++;
483 
484         } while (status == STATUS_OBJECT_NAME_COLLISION);
485 
486         // When this loop exits the count is inflated by one - fix that.
487         deviceNumber--;
488 
489         if (!NT_SUCCESS(status))
490         {
491             TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP,
492                         "DriverEvtDeviceAdd: Can not create a new device, status: 0x%X\n",
493                         status));
494 
495             goto Exit;
496         }
497     }
498 
499     // 8. Fill up basic Device Extension settings and create a remote I/O target for the next-lower driver.
500     //    The reason why we do not use the local I/O target is because we want to be able to close the
501     //    I/O target on surprise removal.
502     {
503         deviceExtension = DeviceGetExtension(device);
504 
505         deviceExtension->Version = 0x01;
506         deviceExtension->Size = sizeof(CDROM_DEVICE_EXTENSION);
507 
508         deviceExtension->DeviceObject = WdfDeviceWdmGetDeviceObject(device);
509         deviceExtension->Device = device;
510         deviceExtension->DriverExtension = driverExtension;
511 
512         deviceExtension->LowerPdo = lowerPdo;
513 
514         deviceExtension->DeviceType = FILE_DEVICE_CD_ROM;   //Always a FILE_DEVICE_CD_ROM for all device it manages.
515         deviceExtension->DeviceName = unicodeDeviceName;
516 
517         deviceExtension->DeviceNumber = deviceNumber;
518     }
519     {
520         WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
521         attributes.ParentObject = deviceExtension->Device;
522 
523         status = WdfIoTargetCreate(deviceExtension->Device,
524                                    &attributes,
525                                    &deviceExtension->IoTarget);
526 
527         if (!NT_SUCCESS(status))
528         {
529             TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP,
530                         "DriverEvtDeviceAdd: Can not create a remote I/O target object, status: 0x%X\n",
531                         status));
532             goto Exit;
533         }
534 
535         WDF_IO_TARGET_OPEN_PARAMS_INIT_EXISTING_DEVICE(&ioTargetOpenParams,
536                                                        WdfDeviceWdmGetAttachedDevice(deviceExtension->Device));
537 
538         status = WdfIoTargetOpen(deviceExtension->IoTarget,
539                                  &ioTargetOpenParams);
540         if (!NT_SUCCESS(status))
541         {
542             TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP,
543                         "DriverEvtDeviceAdd: Can not open a remote I/O target for the next-lower device, status: 0x%X\n",
544                         status));
545 
546             WdfObjectDelete(deviceExtension->IoTarget);
547             deviceExtension->IoTarget = NULL;
548 
549             goto Exit;
550         }
551     }
552 
553     // 9. Claim the device, so that port driver will only accept the commands from CDROM.SYS for this device.
554     // NOTE: The I/O should be issued after the device is started. But we would like to claim
555     // the device as soon as possible, so this legacy behavior is kept.
556     status = DeviceClaimRelease(deviceExtension, FALSE);
557 
558     if (!NT_SUCCESS(status))
559     {
560         // Someone already had this device - we're in trouble
561         goto Exit;
562     }
563     else
564     {
565         deviceClaimed = TRUE;
566     }
567 
568     //
569     // CDROM Queueing Structure
570     //
571     // a. EvtIoInCallerContext (prior to queueing):
572     //      This event will be used ONLY to forward down IOCTLs that come in at PASSIVE LEVEL
573     //      and need to be forwarded down the stack in the original context.
574     //
575     // b. Main input queue: serial queue for main dispatching
576     //      This queue will be used to do all dispatching of requests to serialize
577     //      access to the device.  Any request that was previously completed in
578     //      the Dispatch routines will be completed here.  Anything requiring device
579     //      I/O will be sent through the serial I/O queue.
580     //
581     // 10. Set up IO queues after device being created.
582     //
583     {
584         WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queueConfig,
585                                                WdfIoQueueDispatchSequential);
586 
587         queueConfig.PowerManaged                = WdfFalse;
588 
589 #pragma prefast(push)
590 #pragma prefast(disable: 28155, "a joint handler for read/write cannot be EVT_WDF_IO_QUEUE_IO_READ and EVT_WDF_IO_QUEUE_IO_WRITE simultaneously")
591 #pragma prefast(disable: 28023, "a joint handler for read/write cannot be EVT_WDF_IO_QUEUE_IO_READ and EVT_WDF_IO_QUEUE_IO_WRITE simultaneously")
592         queueConfig.EvtIoRead                   = SequentialQueueEvtIoReadWrite;
593         queueConfig.EvtIoWrite                  = SequentialQueueEvtIoReadWrite;
594 #pragma prefast(pop)
595 
596         queueConfig.EvtIoDeviceControl          = SequentialQueueEvtIoDeviceControl;
597         queueConfig.EvtIoCanceledOnQueue        = SequentialQueueEvtCanceledOnQueue;
598 
599         status = WdfIoQueueCreate(device,
600                                   &queueConfig,
601                                   WDF_NO_OBJECT_ATTRIBUTES,
602                                   &(deviceExtension->SerialIOQueue));
603         if (!NT_SUCCESS(status))
604         {
605             goto Exit;
606         }
607 
608         // this queue is dedicated for file create requests.
609         WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchParallel);
610 
611         queueConfig.PowerManaged = WdfFalse;
612         queueConfig.EvtIoDefault = CreateQueueEvtIoDefault;
613 
614         //Reuse this structure.
615         WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes,
616                                                 CDROM_REQUEST_CONTEXT);
617 
618         attributes.SynchronizationScope = WdfSynchronizationScopeNone;
619         attributes.ExecutionLevel = WdfExecutionLevelPassive;
620 
621         status = WdfIoQueueCreate(device,
622                                   &queueConfig,
623                                   &attributes,
624                                   &(deviceExtension->CreateQueue));
625 
626         if (!NT_SUCCESS(status))
627         {
628             goto Exit;
629         }
630 
631         // Configure the device to use driver created queue for dispatching create.
632         status = WdfDeviceConfigureRequestDispatching(device,
633                                                       deviceExtension->CreateQueue,
634                                                       WdfRequestTypeCreate);
635 
636         if (!NT_SUCCESS(status))
637         {
638             goto Exit;
639         }
640     }
641 
642     // 11. Set the alignment requirements for the device based on the host adapter requirements.
643     //
644     // NOTE: this should have been set when device is attached on device stack,
645     // by keeping this legacy code, we could avoid issue that this value was not correctly set at that time.
646     if (deviceExtension->LowerPdo->AlignmentRequirement > deviceExtension->DeviceObject->AlignmentRequirement)
647     {
648         WdfDeviceSetAlignmentRequirement(deviceExtension->Device,
649                                          deviceExtension->LowerPdo->AlignmentRequirement);
650     }
651 
652     // 12. Initialization of miscellaneous internal properties
653 
654     // CDROMs are not partitionable so starting offset is 0.
655     deviceExtension->StartingOffset.LowPart = 0;
656     deviceExtension->StartingOffset.HighPart = 0;
657 
658     // Set the default geometry for the cdrom to match what NT 4 used.
659     // these values will be used to compute the cylinder count rather
660     // than using it's NT 5.0 defaults.
661     deviceExtension->DiskGeometry.MediaType = RemovableMedia;
662     deviceExtension->DiskGeometry.TracksPerCylinder = 0x40;
663     deviceExtension->DiskGeometry.SectorsPerTrack = 0x20;
664 
665     deviceExtension->DeviceAdditionalData.ReadWriteRetryDelay100nsUnits = WRITE_RETRY_DELAY_DVD_1x;
666 
667     // Clear the SrbFlags and disable synchronous transfers
668     deviceExtension->SrbFlags = SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
669 
670     // Set timeout value in seconds.
671     deviceExtension->TimeOutValue = DeviceGetTimeOutValueFromRegistry();
672     if ((deviceExtension->TimeOutValue > 30 * 60) || // longer than 30 minutes
673         (deviceExtension->TimeOutValue == 0))
674     {
675         deviceExtension->TimeOutValue = SCSI_CDROM_TIMEOUT;
676     }
677 
678     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
679                "DriverEvtDeviceAdd: device timeout is set to %x seconds",
680                deviceExtension->TimeOutValue
681                ));
682 
683 #if (NTDDI_VERSION >= NTDDI_WIN8)
684     deviceExtension->IsVolumeOnlinePending = TRUE;
685 
686     WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchManual);
687 
688     queueConfig.PowerManaged = WdfFalse;
689 
690     status = WdfIoQueueCreate(device,
691                               &queueConfig,
692                               WDF_NO_OBJECT_ATTRIBUTES,
693                               &deviceExtension->ManualVolumeReadyQueue);
694 
695     if (!NT_SUCCESS(status))
696     {
697         goto Exit;
698     }
699 #endif
700 
701     // 13. Initialize the stuff related to media locking
702     WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
703     attributes.ParentObject = deviceExtension->Device;
704     status = WdfWaitLockCreate(&attributes,
705                                &deviceExtension->EjectSynchronizationLock);
706 
707     deviceExtension->LockCount = 0;
708 
709     // 14. Initialize context structures needed for asynchronous release queue and power requests
710 
711     if (NT_SUCCESS(status))
712     {
713         status = DeviceInitReleaseQueueContext(deviceExtension);
714     }
715 
716     if (NT_SUCCESS(status))
717     {
718         status = DeviceInitPowerContext(deviceExtension);
719     }
720 
721     // 15. Create external access points other than device name.
722     if (NT_SUCCESS(status))
723     {
724         status = DeviceCreateWellKnownName(deviceExtension);
725     }
726 
727     // 16. Query session id from the PDO.
728     if (NT_SUCCESS(status))
729     {
730         status = IoGetDevicePropertyData(deviceExtension->LowerPdo,
731                                          &DEVPKEY_Device_SessionId,
732                                          0,
733                                          0,
734                                          sizeof(devicePropertySessionId),
735                                          &devicePropertySessionId,
736                                          &devicePropertySize,
737                                          &devicePropertyType);
738 
739         if (!NT_SUCCESS(status))
740         {
741             // The device is global.
742             devicePropertySessionId = INVALID_SESSION;
743             status = STATUS_SUCCESS;
744         }
745     }
746 
747     // 17. Register interfaces for this device.
748     if (NT_SUCCESS(status))
749     {
750         status = DeviceRegisterInterface(deviceExtension, CdRomDeviceInterface);
751     }
752 
753     if (NT_SUCCESS(status))
754     {
755         // If this is a per-session DO, don't register for mount interface so that
756         // mountmgr will not automatically assign a drive letter.
757         if (devicePropertySessionId == INVALID_SESSION)
758         {
759             status = DeviceRegisterInterface(deviceExtension, MountedDeviceInterface);
760         }
761     }
762 
763     // 18. Initialize the shutdown/flush lock
764     if (NT_SUCCESS(status))
765     {
766         WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
767         attributes.ParentObject = deviceExtension->Device;
768 
769         status = WdfWaitLockCreate(&attributes, &deviceExtension->ShutdownFlushWaitLock);
770         if (!NT_SUCCESS(status))
771         {
772             TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP,
773                         "DriverEvtDeviceAdd: Cannot create shutdown/flush waitlock, status: 0x%X\n",
774                         status));
775         }
776     }
777 
778     // 19. Initialize the work item that is used to initiate asynchronous reads/writes
779     if (NT_SUCCESS(status))
780     {
781         WDF_WORKITEM_CONFIG workItemConfig;
782         WDF_OBJECT_ATTRIBUTES workItemAttributes;
783 
784         WDF_WORKITEM_CONFIG_INIT(&workItemConfig,
785                                  ReadWriteWorkItemRoutine
786                                  );
787 
788         WDF_OBJECT_ATTRIBUTES_INIT(&workItemAttributes);
789         workItemAttributes.ParentObject = deviceExtension->Device;
790 
791         status = WdfWorkItemCreate(&workItemConfig,
792                                    &workItemAttributes,
793                                    &deviceExtension->ReadWriteWorkItem
794                                    );
795 
796         if (!NT_SUCCESS(status))
797         {
798             TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_INIT,
799                         "DriverEvtDeviceAdd: Cannot create read/write work item, status: 0x%X\n",
800                         status));
801         }
802     }
803 
804     // 20. Initialize the work item that is used to process most IOCTLs at PASSIVE_LEVEL.
805     if (NT_SUCCESS(status))
806     {
807         WDF_WORKITEM_CONFIG workItemConfig;
808         WDF_OBJECT_ATTRIBUTES workItemAttributes;
809 
810         WDF_WORKITEM_CONFIG_INIT(&workItemConfig,
811                                  IoctlWorkItemRoutine
812                                  );
813 
814         WDF_OBJECT_ATTRIBUTES_INIT(&workItemAttributes);
815         workItemAttributes.ParentObject = deviceExtension->Device;
816 
817         status = WdfWorkItemCreate(&workItemConfig,
818                                    &workItemAttributes,
819                                    &deviceExtension->IoctlWorkItem
820                                    );
821 
822         if (!NT_SUCCESS(status))
823         {
824             TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_INIT,
825                         "DriverEvtDeviceAdd: Cannot create ioctl work item, status: 0x%X\n",
826                         status));
827         }
828     }
829 
830 
831 Exit:
832 
833     if (!NT_SUCCESS(status))
834     {
835         FREE_POOL(wideDeviceName);
836 
837         if (deviceExtension != NULL)
838         {
839             RtlInitUnicodeString(&deviceExtension->DeviceName, NULL);
840         }
841 
842         // Release the device with the port driver, if it was claimed
843         if ((deviceExtension != NULL) && deviceClaimed)
844         {
845             DeviceClaimRelease(deviceExtension, TRUE);
846         }
847         deviceClaimed = FALSE;
848     }
849 
850     return status;
851 }
852 
853 
854 VOID
855 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DeviceEvtCleanup(_In_ WDFOBJECT Device)856 DeviceEvtCleanup(
857     _In_ WDFOBJECT Device
858     )
859 /*++
860 Routine Description:
861 
862     Free all the resources allocated in DriverEvtDeviceAdd.
863 
864 Arguments:
865 
866     Device - handle to a WDF Device object.
867 
868 Return Value:
869 
870     VOID.
871 
872 --*/
873 {
874     WDFDEVICE                device = (WDFDEVICE)Device;
875     PCDROM_DEVICE_EXTENSION  deviceExtension = NULL;
876 
877     PAGED_CODE ();
878 
879     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
880                 "WDFDEVICE %p cleanup: The device is about to be destroyed.\n",
881                 device));
882 
883     deviceExtension = DeviceGetExtension(device);
884 
885     FREE_POOL(deviceExtension->DeviceName.Buffer);
886     RtlInitUnicodeString(&deviceExtension->DeviceName, NULL);
887 
888     if (deviceExtension->DeviceAdditionalData.WellKnownName.Buffer != NULL)
889     {
890         IoDeleteSymbolicLink(&deviceExtension->DeviceAdditionalData.WellKnownName);
891     }
892 
893     FREE_POOL(deviceExtension->DeviceAdditionalData.WellKnownName.Buffer);
894     RtlInitUnicodeString(&deviceExtension->DeviceAdditionalData.WellKnownName, NULL);
895 
896     return;
897 }
898 
899 
900 VOID
901 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DeviceEvtSelfManagedIoCleanup(_In_ WDFDEVICE Device)902 DeviceEvtSelfManagedIoCleanup(
903     _In_ WDFDEVICE    Device
904     )
905 /*++
906 
907 Routine Description:
908 
909     this function is called when the device is removed.
910     release the ownership of the device, release allocated resources.
911 
912 Arguments:
913 
914     Device - Handle to device object
915 
916 Return Value:
917 
918     None.
919 
920 --*/
921 {
922     NTSTATUS                status;
923     PCDROM_DEVICE_EXTENSION deviceExtension = NULL;
924 
925     PAGED_CODE ();
926 
927     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP,
928                 "DeviceEvtSelfManagedIoCleanup: WDFDEVICE %p is being stopped.\n",
929                 Device));
930 
931     // extract the device and driver extensions
932     deviceExtension = DeviceGetExtension(Device);
933 
934     // Purge unprocessed requests, stop the IO queues.
935     // Incoming request will be completed with STATUS_INVALID_DEVICE_STATE status.
936     WdfIoQueuePurge(deviceExtension->SerialIOQueue, WDF_NO_EVENT_CALLBACK, WDF_NO_CONTEXT);
937     WdfIoQueuePurge(deviceExtension->CreateQueue, WDF_NO_EVENT_CALLBACK, WDF_NO_CONTEXT);
938 
939     // Close the IoTarget so that we are sure there are no outstanding I/Os in the stack.
940     if (deviceExtension->IoTarget)
941     {
942         WdfIoTargetClose(deviceExtension->IoTarget);
943     }
944 
945     // Release the device
946     if (!deviceExtension->SurpriseRemoved)
947     {
948         status = DeviceClaimRelease(deviceExtension, TRUE);  //status is mainly for debugging. we don't really care.
949         UNREFERENCED_PARAMETER(status);             //defensive coding, avoid PREFAST warning.
950     }
951 
952     // Be sure to flush the DPCs as the READ/WRITE timer routine may still be running
953     // during device removal.  This call may take a while to complete.
954     KeFlushQueuedDpcs();
955 
956     // Release all the memory that we have allocated.
957 
958     DeviceDeallocateMmcResources(Device);
959     ScratchBuffer_Deallocate(deviceExtension);
960     RtlZeroMemory(&(deviceExtension->DeviceAdditionalData.Mmc), sizeof(CDROM_MMC_EXTENSION));
961 
962     FREE_POOL(deviceExtension->DeviceDescriptor);
963     FREE_POOL(deviceExtension->AdapterDescriptor);
964     FREE_POOL(deviceExtension->PowerDescriptor);
965     FREE_POOL(deviceExtension->SenseData);
966 
967     if (deviceExtension->DeviceAdditionalData.CachedInquiryData != NULL)
968     {
969         FREE_POOL(deviceExtension->DeviceAdditionalData.CachedInquiryData);
970         deviceExtension->DeviceAdditionalData.CachedInquiryDataByteCount = 0;
971     }
972 
973     FREE_POOL(deviceExtension->PrivateFdoData);
974 
975     DeviceReleaseMcnResources(deviceExtension);
976 
977     DeviceReleaseZPODDResources(deviceExtension);
978 
979     // Keep the system-wide CDROM count accurate, as programs use this info to
980     // know when they have found all the cdroms in a system.
981     IoGetConfigurationInformation()->CdRomCount--;
982 
983     deviceExtension->PartitionLength.QuadPart = 0;
984 
985     // All WDF objects related to Device will be automatically released
986     // when the root object is deleted. No need to release them manually.
987 
988     return;
989 }
990 
991 NTSTATUS
992 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DeviceEvtD0Entry(_In_ WDFDEVICE Device,_In_ WDF_POWER_DEVICE_STATE PreviousState)993 DeviceEvtD0Entry(
994     _In_ WDFDEVICE Device,
995     _In_ WDF_POWER_DEVICE_STATE PreviousState
996     )
997 /*++
998 
999 Routine Description:
1000 
1001     This function is called when the device is coming back from a lower power state to D0.
1002     This function cannot be placed in a pageable section.
1003 
1004 Arguments:
1005 
1006     Device - Handle to device object
1007     PreviousState - Power state the device was in.
1008 
1009 Return Value:
1010 
1011     NTSTATUS: alway STATUS_SUCCESS
1012 
1013 --*/
1014 {
1015     PCDROM_DEVICE_EXTENSION     deviceExtension;
1016     NTSTATUS                    status = STATUS_SUCCESS;
1017     PZERO_POWER_ODD_INFO        zpoddInfo = NULL;
1018     STORAGE_IDLE_POWERUP_REASON powerupReason = {0};
1019 
1020     UNREFERENCED_PARAMETER(PreviousState);
1021     deviceExtension = DeviceGetExtension(Device);
1022 
1023     // Make certain not to do anything before properly initialized
1024     if (deviceExtension->IsInitialized)
1025     {
1026         zpoddInfo = deviceExtension->ZeroPowerODDInfo;
1027 
1028         if (zpoddInfo != NULL)
1029         {
1030             if (zpoddInfo->InZeroPowerState != FALSE)
1031             {
1032                 // We just woke up from Zero Power state
1033                 zpoddInfo->InZeroPowerState = FALSE;
1034                 zpoddInfo->RetryFirstCommand = TRUE;
1035                 zpoddInfo->BecomingReadyRetryCount = BECOMING_READY_RETRY_COUNT;
1036 
1037                 status = DeviceZPODDGetPowerupReason(deviceExtension, &powerupReason);
1038 
1039                 if (NT_SUCCESS(status) &&
1040                     (powerupReason.PowerupReason == StoragePowerupDeviceAttention))
1041                 {
1042                     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER,
1043                                 "DeviceEvtD0Entry: Device has left zero power state due to eject button pressed\n"
1044                                 ));
1045 
1046                     // This wake-up is caused by user pressing the eject button.
1047                     // In case of drawer type, we need to soft eject the tray to emulate the effect.
1048                     // Note that the first command to the device after power resumed will
1049                     // be terminated with CHECK CONDITION status with sense code 6/29/00,
1050                     // but we already have a retry logic to handle this.
1051                     if ((zpoddInfo->LoadingMechanism == LOADING_MECHANISM_TRAY) && (zpoddInfo->Load == 0))    // Drawer
1052                     {
1053                         DeviceSendIoctlAsynchronously(deviceExtension, IOCTL_STORAGE_EJECT_MEDIA, deviceExtension->DeviceObject);
1054                     }
1055                 }
1056                 else
1057                 {
1058                     // This wake-up is caused by non-cached CDB received or a 3rd-party driver
1059                     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER,
1060                                 "DeviceEvtD0Entry: Device has left zero power state due to IO received\n"
1061                                 ));
1062 
1063                 }
1064             }
1065         }
1066 
1067         DeviceEnableMainTimer(deviceExtension);
1068     }
1069 
1070     return STATUS_SUCCESS;
1071 }
1072 
1073 NTSTATUS
1074 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DeviceEvtD0Exit(_In_ WDFDEVICE Device,_In_ WDF_POWER_DEVICE_STATE TargetState)1075 DeviceEvtD0Exit(
1076     _In_ WDFDEVICE Device,
1077     _In_ WDF_POWER_DEVICE_STATE TargetState
1078     )
1079 /*++
1080 
1081 Routine Description:
1082 
1083     This function is called when the device is entering lower powe state from D0 or it's removed.
1084     We only care about the case of device entering D3.
1085     The purpose of this function is to send SYNC CACHE command and STOP UNIT command if it's necessary.
1086 
1087 Arguments:
1088 
1089     Device - Handle to device object
1090     TargetState - Power state the device is entering.
1091 
1092 Return Value:
1093 
1094     NTSTATUS: alway STATUS_SUCCESS
1095 
1096 --*/
1097 {
1098     NTSTATUS                status = STATUS_SUCCESS;
1099     PCDROM_DEVICE_EXTENSION deviceExtension = NULL;
1100     PZERO_POWER_ODD_INFO    zpoddInfo = NULL;
1101 
1102     PAGED_CODE ();
1103 
1104     deviceExtension = DeviceGetExtension(Device);
1105     zpoddInfo = deviceExtension->ZeroPowerODDInfo;
1106 
1107     // we only process the situation that the device is going into D3.
1108     if ((TargetState != WdfPowerDeviceD3) &&
1109         (TargetState != WdfPowerDeviceD3Final))
1110     {
1111         return STATUS_SUCCESS;
1112     }
1113 
1114     // Stop the main timer
1115     DeviceDisableMainTimer(deviceExtension);
1116 
1117     // note: do not stop CreateQueue as the create request can be handled by port driver even the device is in D3 status.
1118 
1119     // If initialization was not finished or the device was removed, we cannot interact
1120     // with it device, so we have to exit
1121     if ((!deviceExtension->IsInitialized) || deviceExtension->SurpriseRemoved)
1122     {
1123         return STATUS_SUCCESS;
1124     }
1125 
1126 
1127 #ifdef DBG
1128     #if (WINVER >= 0x0601)
1129     // this API is introduced in Windows7
1130     {
1131         ULONG   secondsRemaining = 0;
1132         BOOLEAN watchdogTimeSupported = FALSE;
1133 
1134         watchdogTimeSupported = PoQueryWatchdogTime(deviceExtension->LowerPdo, &secondsRemaining);
1135         UNREFERENCED_PARAMETER(watchdogTimeSupported);
1136     }
1137     #endif
1138 #endif
1139 
1140     deviceExtension->PowerDownInProgress = TRUE;
1141 
1142     status = PowerContextBeginUse(deviceExtension);
1143 
1144     deviceExtension->PowerContext.Options.PowerDown = TRUE;
1145 
1146     // Step 1. LOCK QUEUE
1147     if (NT_SUCCESS(status) &&
1148         (TargetState != WdfPowerDeviceD3Final))
1149     {
1150         status = DeviceSendPowerDownProcessRequest(deviceExtension, NULL, NULL);
1151 
1152         if (NT_SUCCESS(status))
1153         {
1154             deviceExtension->PowerContext.Options.LockQueue = TRUE;
1155         }
1156 
1157         // Ignore failure.
1158         status = STATUS_SUCCESS;
1159     }
1160 
1161     deviceExtension->PowerContext.PowerChangeState.PowerDown++;
1162 
1163     // Step 2. QUIESCE QUEUE
1164     if (NT_SUCCESS(status) &&
1165         (TargetState != WdfPowerDeviceD3Final))
1166     {
1167         status = DeviceSendPowerDownProcessRequest(deviceExtension, NULL, NULL);
1168         UNREFERENCED_PARAMETER(status);
1169         // We don't care about the status.
1170         status = STATUS_SUCCESS;
1171     }
1172 
1173     deviceExtension->PowerContext.PowerChangeState.PowerDown++;
1174 
1175     // Step 3. SYNC CACHE command should be sent to drive if the media is currently writable.
1176     if (NT_SUCCESS(status) &&
1177         deviceExtension->DeviceAdditionalData.Mmc.WriteAllowed)
1178     {
1179         status = DeviceSendPowerDownProcessRequest(deviceExtension, NULL, NULL);
1180         UNREFERENCED_PARAMETER(status);
1181         status = STATUS_SUCCESS;
1182     }
1183 
1184     deviceExtension->PowerContext.PowerChangeState.PowerDown++;
1185 
1186     // Step 4. STOP UNIT
1187     if (NT_SUCCESS(status) &&
1188         !TEST_FLAG(deviceExtension->ScanForSpecialFlags, CDROM_SPECIAL_DISABLE_SPIN_DOWN))
1189     {
1190         status = DeviceSendPowerDownProcessRequest(deviceExtension, NULL, NULL);
1191         UNREFERENCED_PARAMETER(status);
1192         status = STATUS_SUCCESS;
1193     }
1194 
1195     if (TargetState == WdfPowerDeviceD3Final)
1196     {
1197         // We're done with the power context.
1198         PowerContextEndUse(deviceExtension);
1199     }
1200 
1201     // Bumping the media  change count  will force the file system to verify the volume when we resume
1202     SET_FLAG(deviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME);
1203     InterlockedIncrement((PLONG)&deviceExtension->MediaChangeCount);
1204 
1205     // If this power down is caused by Zero Power ODD, we should mark the device as in ZPODD mode.
1206     if (zpoddInfo != NULL)
1207     {
1208         zpoddInfo->InZeroPowerState = TRUE;
1209 
1210         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER,
1211                     "Device has entered zero power state\n"
1212                     ));
1213     }
1214 
1215     deviceExtension->PowerDownInProgress = FALSE;
1216 
1217     return STATUS_SUCCESS;
1218 }
1219 
1220 
1221 VOID
1222 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DeviceEvtSurpriseRemoval(_In_ WDFDEVICE Device)1223 DeviceEvtSurpriseRemoval(
1224     _In_ WDFDEVICE    Device
1225     )
1226 /*++
1227 
1228 Routine Description:
1229 
1230     this function is called when the device is surprisely removed.
1231     Stop all IO queues so that there will be no more request being sent down.
1232 
1233 Arguments:
1234 
1235     Device - Handle to device object
1236 
1237 Return Value:
1238 
1239     None.
1240 
1241 --*/
1242 {
1243     PCDROM_DEVICE_EXTENSION deviceExtension = NULL;
1244 
1245     PAGED_CODE();
1246 
1247     deviceExtension = DeviceGetExtension(Device);
1248 
1249     deviceExtension->SurpriseRemoved = TRUE;
1250 
1251     // Stop the main timer
1252     DeviceDisableMainTimer(deviceExtension);
1253 
1254     // legacy behavior to set partition length to be 0.
1255     deviceExtension->PartitionLength.QuadPart = 0;
1256 
1257     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
1258                 "Surprisely remove a WDFDEVICE %p\n", Device));
1259 
1260     return;
1261 }
1262 
1263 
1264 VOID
1265 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
CreateQueueEvtIoDefault(_In_ WDFQUEUE Queue,_In_ WDFREQUEST Request)1266 CreateQueueEvtIoDefault(
1267     _In_ WDFQUEUE Queue,
1268     _In_ WDFREQUEST Request
1269     )
1270 /*++
1271 
1272 Routine Description:
1273 
1274     this function is called when CREATE irp comes.
1275     setup FileObject context fields, so it can be used to track MCN or exclusive lock/unlock.
1276 
1277 Arguments:
1278 
1279     Queue - Handle to device queue
1280 
1281     Request - the creation request
1282 
1283 Return Value:
1284 
1285     None
1286 
1287 --*/
1288 {
1289     WDFFILEOBJECT           fileObject = WdfRequestGetFileObject(Request);
1290     WDFDEVICE               device = WdfIoQueueGetDevice(Queue);
1291     NTSTATUS                status = STATUS_SUCCESS;
1292     PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(device);
1293     PFILE_OBJECT_CONTEXT    fileObjectContext = NULL;
1294 
1295     PAGED_CODE();
1296 
1297     if (fileObject == NULL) {
1298 
1299         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_QUEUE,
1300                     "Error: received a file create request with file object set to NULL\n"));
1301 
1302         RequestCompletion(deviceExtension, Request, STATUS_INTERNAL_ERROR, 0);
1303         return;
1304     }
1305 
1306     fileObjectContext = FileObjectGetContext(fileObject);
1307 
1308     // Initialize this WDFFILEOBJECT's context
1309     fileObjectContext->DeviceObject = device;
1310     fileObjectContext->FileObject = fileObject;
1311     fileObjectContext->LockCount = 0;
1312     fileObjectContext->McnDisableCount = 0;
1313     fileObjectContext->EnforceStreamingRead = FALSE;
1314     fileObjectContext->EnforceStreamingWrite = FALSE;
1315 
1316     // send down the create synchronously
1317     status = DeviceSendRequestSynchronously(device, Request, FALSE);
1318 
1319     // Need to complete the request in this routine.
1320     RequestCompletion(deviceExtension, Request, status, WdfRequestGetInformation(Request));
1321 
1322     return;
1323 }
1324 
1325 VOID
1326 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DeviceEvtFileClose(_In_ WDFFILEOBJECT FileObject)1327 DeviceEvtFileClose(
1328     _In_ WDFFILEOBJECT FileObject
1329     )
1330 /*++
1331 
1332 Routine Description:
1333 
1334     this function is called when CLOSE irp comes.
1335     clean up MCN / Lock if necessary
1336 
1337 Arguments:
1338 
1339     FileObject - WDF file object created for the irp.
1340 
1341 Return Value:
1342 
1343     None
1344 
1345 --*/
1346 {
1347     NTSTATUS                status = STATUS_SUCCESS;
1348 
1349     PAGED_CODE();
1350 
1351     if (FileObject != NULL)
1352     {
1353         WDFDEVICE               device = WdfFileObjectGetDevice(FileObject);
1354         PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(device);
1355         PCDROM_DATA             cdData = &(deviceExtension->DeviceAdditionalData);
1356         PFILE_OBJECT_CONTEXT    fileObjectContext = FileObjectGetContext(FileObject);
1357 
1358         // cleanup locked media tray
1359         status = DeviceCleanupProtectedLocks(deviceExtension, fileObjectContext);
1360         if (!NT_SUCCESS(status))
1361         {
1362             TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
1363                         "Failed to cleanup protected locks for WDFDEVICE %p, %!STATUS!\n", device, status));
1364         }
1365 
1366         // cleanup disabled MCN
1367         status = DeviceCleanupDisableMcn(deviceExtension, fileObjectContext);
1368         if (!NT_SUCCESS(status))
1369         {
1370             TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
1371                         "Failed to disable MCN for WDFDEVICE %p, %!STATUS!\n", device, status));
1372         }
1373 
1374         // cleanup exclusive access
1375         if (EXCLUSIVE_MODE(cdData) && EXCLUSIVE_OWNER(cdData, FileObject))
1376         {
1377             status = DeviceUnlockExclusive(deviceExtension, FileObject, FALSE);
1378             if (!NT_SUCCESS(status))
1379             {
1380                 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
1381                             "Failed to release exclusive lock for WDFDEVICE %p, %!STATUS!\n", device, status));
1382             }
1383         }
1384     }
1385 
1386     return;
1387 }
1388 
_IRQL_requires_max_(PASSIVE_LEVEL)1389 _IRQL_requires_max_(PASSIVE_LEVEL)
1390 NTSTATUS
1391 DeviceCleanupProtectedLocks(
1392     _In_ PCDROM_DEVICE_EXTENSION  DeviceExtension,
1393     _In_ PFILE_OBJECT_CONTEXT     FileObjectContext
1394     )
1395 /*++
1396 
1397 Routine Description:
1398 
1399     this function removes protected locks for the handle
1400 
1401 Arguments:
1402 
1403     DeviceExtension - device context
1404 
1405     FileObject - WDF file object created for the irp.
1406 
1407 Return Value:
1408 
1409     NTSTATUS
1410 
1411 --*/
1412 {
1413     NTSTATUS    status = STATUS_SUCCESS;
1414 
1415     PAGED_CODE();
1416 
1417     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
1418                 "CleanupProtectedLocks called for WDFDEVICE %p, WDFFILEOBJECT %p, locked %d times.\n",
1419                 DeviceExtension->Device, FileObjectContext->FileObject, FileObjectContext->LockCount));
1420 
1421     // Synchronize with ejection and ejection control requests.
1422     WdfWaitLockAcquire(DeviceExtension->EjectSynchronizationLock, NULL);
1423 
1424     // For each secure lock on this handle decrement the secured lock count
1425     // for the FDO.  Keep track of the new value.
1426     if (FileObjectContext->LockCount != 0)
1427     {
1428         DeviceExtension->ProtectedLockCount -= FileObjectContext->LockCount;
1429         FileObjectContext->LockCount = 0;
1430 
1431         // If the new lock count has been dropped to zero then issue a lock
1432         // command to the device.
1433         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
1434                     "FDO secured lock count = %d "
1435                     "lock count = %d\n",
1436                     DeviceExtension->ProtectedLockCount,
1437                     DeviceExtension->LockCount));
1438 
1439         if ((DeviceExtension->ProtectedLockCount == 0) && (DeviceExtension->LockCount == 0))
1440         {
1441             SCSI_REQUEST_BLOCK  srb = {0};
1442             PCDB                cdb = (PCDB) &(srb.Cdb);
1443 
1444             srb.CdbLength = 6;
1445 
1446             cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
1447 
1448             // TRUE - prevent media removal.
1449             // FALSE - allow media removal.
1450             cdb->MEDIA_REMOVAL.Prevent = FALSE;
1451 
1452             // Set timeout value.
1453             srb.TimeOutValue = DeviceExtension->TimeOutValue;
1454             status = DeviceSendSrbSynchronously(DeviceExtension->Device,
1455                                                 &srb,
1456                                                 NULL,
1457                                                 0,
1458                                                 FALSE,
1459                                                 NULL);
1460 
1461             TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
1462                         "Allow media removal (unlock) request to drive returned %!STATUS!\n",
1463                         status));
1464         }
1465     }
1466 
1467     WdfWaitLockRelease(DeviceExtension->EjectSynchronizationLock);
1468 
1469     return status;
1470 }
1471 
1472 
_IRQL_requires_max_(APC_LEVEL)1473 _IRQL_requires_max_(APC_LEVEL)
1474 NTSTATUS
1475 DeviceCleanupDisableMcn(
1476     _In_ PCDROM_DEVICE_EXTENSION  DeviceExtension,
1477     _In_ PFILE_OBJECT_CONTEXT     FileObjectContext
1478     )
1479 /*++
1480 
1481 Routine Description:
1482 
1483     cleanup the MCN disable count for the handle
1484 
1485 Arguments:
1486 
1487     DeviceExtension - device context
1488 
1489     FileObject - WDF file object created for the irp.
1490 
1491 Return Value:
1492 
1493     NTSTATUS
1494 
1495 --*/
1496 {
1497     PAGED_CODE();
1498 
1499     TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT,
1500                 "CleanupDisableMcn called for WDFDEVICE %p, WDFFILEOBJECT %p, locked %d times.\n",
1501                 DeviceExtension->Device, FileObjectContext->FileObject, FileObjectContext->McnDisableCount));
1502 
1503     // For each secure lock on this handle decrement the secured lock count
1504     // for the FDO.  Keep track of the new value.
1505     while (FileObjectContext->McnDisableCount != 0)
1506     {
1507         DeviceEnableMediaChangeDetection(DeviceExtension, FileObjectContext, TRUE);
1508     }
1509 
1510     return STATUS_SUCCESS;
1511 }
1512 
1513 VOID
NormalizeIoctl(_Inout_ PWDF_REQUEST_PARAMETERS requestParameters)1514 NormalizeIoctl(
1515     _Inout_ PWDF_REQUEST_PARAMETERS  requestParameters
1516     )
1517 {
1518     ULONG ioctlCode;
1519     ULONG baseCode;
1520     ULONG functionCode;
1521 
1522     // if this is a class driver ioctl then we need to change the base code
1523     // to IOCTL_STORAGE_BASE so that the switch statement can handle it.
1524     //
1525     // WARNING - currently the scsi class ioctl function codes are between
1526     // 0x200 & 0x300.  this routine depends on that fact
1527     ioctlCode = requestParameters->Parameters.DeviceIoControl.IoControlCode;
1528     baseCode = DEVICE_TYPE_FROM_CTL_CODE(ioctlCode);
1529     functionCode = (ioctlCode & (~0xffffc003)) >> 2;
1530 
1531     if ((baseCode == IOCTL_SCSI_BASE) ||
1532         (baseCode == IOCTL_DISK_BASE) ||
1533         (baseCode == IOCTL_TAPE_BASE) ||
1534         (baseCode == IOCTL_DVD_BASE) ||
1535         (baseCode == IOCTL_CDROM_BASE))
1536         //IOCTL_STORAGE_BASE does not need to be converted.
1537     {
1538         if((functionCode >= 0x200) && (functionCode <= 0x300))
1539         {
1540             ioctlCode = (ioctlCode & 0x0000ffff) | CTL_CODE(IOCTL_STORAGE_BASE, 0, 0, 0);
1541 
1542             TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL,
1543                         "IOCTL code recalibrate, New ioctl code is %lx\n",
1544                         ioctlCode));
1545 
1546             // Set the code into request parameters, then "requestParameters" needs to be used for dispatch functions.
1547             requestParameters->Parameters.DeviceIoControl.IoControlCode = ioctlCode;
1548         }
1549     }
1550 }
1551 
1552 VOID
1553 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DeviceEvtIoInCallerContext(_In_ WDFDEVICE Device,_In_ WDFREQUEST Request)1554 DeviceEvtIoInCallerContext(
1555     _In_ WDFDEVICE    Device,
1556     _In_ WDFREQUEST   Request
1557     )
1558 /*++
1559 Routine Description:
1560 
1561     Responds to EvtIoInCallerContext events from KMDF
1562     It calls different functions to process different type of IOCTLs.
1563 
1564 Arguments:
1565 
1566     Device - handle to a WDF Device object
1567 
1568     Request - handle to the incoming WDF Request object
1569 
1570 Return Value:
1571 
1572     VOID.
1573 
1574 --*/
1575 {
1576     NTSTATUS                status  = STATUS_SUCCESS;
1577     PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device);
1578     PCDROM_REQUEST_CONTEXT  requestContext = RequestGetContext(Request);
1579     WDF_REQUEST_PARAMETERS  requestParameters;
1580 
1581     requestContext->DeviceExtension = deviceExtension;
1582 
1583     // set the received time
1584     RequestSetReceivedTime(Request);
1585 
1586     // get the request parameters
1587     WDF_REQUEST_PARAMETERS_INIT(&requestParameters);
1588     WdfRequestGetParameters(Request, &requestParameters);
1589 
1590     if (requestParameters.Type == WdfRequestTypeDeviceControl)
1591     {
1592         BOOLEAN                         processed = FALSE;
1593         PCDROM_DATA                     cdData = &(deviceExtension->DeviceAdditionalData);
1594         PMEDIA_CHANGE_DETECTION_INFO    info = deviceExtension->MediaChangeDetectionInfo;
1595 
1596         if (requestParameters.Parameters.DeviceIoControl.IoControlCode != IOCTL_MCN_SYNC_FAKE_IOCTL)
1597         {
1598             TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
1599                         "Receiving IOCTL: %lx\n",
1600                         requestParameters.Parameters.DeviceIoControl.IoControlCode));
1601         }
1602         else
1603         {
1604             TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL,
1605                         "Receiving IOCTL: %lx\n",
1606                         requestParameters.Parameters.DeviceIoControl.IoControlCode));
1607         }
1608 
1609         // If the device is in exclusive mode, check whether the request is from
1610         // the handle that locked the device.
1611         if (EXCLUSIVE_MODE(cdData) && !EXCLUSIVE_OWNER(cdData, WdfRequestGetFileObject(Request)))
1612         {
1613             BOOLEAN isBlocked = FALSE;
1614 
1615             status = RequestIsIoctlBlockedByExclusiveAccess(Request, &isBlocked);
1616             UNREFERENCED_PARAMETER(status); //defensive coding, avoid PREFAST warning.
1617 
1618             if (isBlocked)
1619             {
1620                 if ((requestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_STORAGE_EVENT_NOTIFICATION) &&
1621                     (info != NULL) && (info->AsynchronousNotificationSupported != FALSE))
1622                 {
1623                     // If AN is supported and we receive a signal but we can't send down GESN
1624                     // due to exclusive lock, we should save it and fire a GESN when it's unlocked.
1625                     // We just need true/false here and don't need count because we will keep sending
1626                     // GESN until we deplete all events.
1627                     info->ANSignalPendingDueToExclusiveLock = TRUE;
1628                 }
1629 
1630                 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL,
1631                             "Access Denied! Device in exclusive mode.Failing Ioctl %lx\n",
1632                             requestParameters.Parameters.DeviceIoControl.IoControlCode));
1633                 RequestCompletion(deviceExtension, Request, STATUS_ACCESS_DENIED, 0);
1634 
1635                 return;
1636             }
1637         }
1638 
1639         NormalizeIoctl(&requestParameters);
1640 
1641         // 1. All requests that don't need to access device can be processed immediately
1642         if (!processed)
1643         {
1644             processed = RequestDispatchProcessDirectly(Device, Request, requestParameters);
1645         }
1646 
1647         // 2. Requests that should be put in sequential queue.
1648         if (!processed)
1649         {
1650             processed = RequestDispatchToSequentialQueue(Device, Request, requestParameters);
1651         }
1652 
1653         // 3. Requests that need to be processed sequentially and in caller's context.
1654         if (!processed)
1655         {
1656             processed = RequestDispatchSyncWithSequentialQueue(Device, Request, requestParameters);
1657         }
1658 
1659         // 4. Special requests that needs different process in different cases.
1660         if (!processed)
1661         {
1662             processed = RequestDispatchSpecialIoctls(Device, Request, requestParameters);
1663         }
1664 
1665         // 5. This is default behavior for unknown IOCTLs. To pass it to lower level.
1666         if (!processed)
1667         {
1668             processed = RequestDispatchUnknownRequests(Device, Request, requestParameters);
1669         }
1670 
1671         // All requests should be processed already.
1672         NT_ASSERT(processed);
1673         UNREFERENCED_PARAMETER(processed); //defensive coding, avoid PREFAST warning.
1674     }
1675     else if (requestParameters.Type == WdfRequestTypeDeviceControlInternal)
1676     {
1677         RequestProcessInternalDeviceControl(Request, deviceExtension);
1678     }
1679     else
1680     {
1681         // Requests other than IOCTLs will be forwarded to default queue.
1682         status = WdfDeviceEnqueueRequest(Device, Request);
1683         if (!NT_SUCCESS(status))
1684         {
1685             RequestCompletion(deviceExtension, Request, status, WdfRequestGetInformation(Request));
1686         }
1687     }
1688 
1689     return;
1690 }
1691 
1692 
1693 BOOLEAN
RequestDispatchProcessDirectly(_In_ WDFDEVICE Device,_In_ WDFREQUEST Request,_In_ WDF_REQUEST_PARAMETERS RequestParameters)1694 RequestDispatchProcessDirectly(
1695     _In_ WDFDEVICE              Device,
1696     _In_ WDFREQUEST             Request,
1697     _In_ WDF_REQUEST_PARAMETERS RequestParameters
1698     )
1699 /*++
1700 Routine Description:
1701 
1702     These requests can be processed in a non-serialized manner, most of them don't need to access device.
1703 
1704 Arguments:
1705 
1706     Device - handle to a WDF Device object
1707 
1708     Request - handle to the incoming WDF Request object
1709 
1710     RequestParameters - request parameters
1711 
1712 Return Value:
1713 
1714     BOOLEAN - TRUE (request processed); FALSE (request is not processed in this function).
1715 
1716 --*/
1717 {
1718     NTSTATUS                status = STATUS_SUCCESS;
1719     BOOLEAN                 processed = FALSE;
1720     size_t                  dataLength = 0;
1721 
1722     PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device);
1723     ULONG                   ioctlCode = RequestParameters.Parameters.DeviceIoControl.IoControlCode;
1724 
1725     switch (ioctlCode)
1726     {
1727 
1728     case IOCTL_CDROM_GET_INQUIRY_DATA:
1729     {
1730         status = RequestHandleGetInquiryData(deviceExtension, Request, RequestParameters, &dataLength);
1731 
1732         processed = TRUE;
1733         break; // complete the irp
1734     }
1735 
1736     case IOCTL_STORAGE_GET_MEDIA_TYPES_EX:
1737     {
1738         status = RequestHandleGetMediaTypeEx(deviceExtension, Request, &dataLength);
1739 
1740         processed = TRUE;
1741         break; // complete the irp
1742     }
1743 
1744     case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID:
1745     {
1746         status = RequestHandleMountQueryUniqueId(deviceExtension, Request, RequestParameters, &dataLength);
1747 
1748         processed = TRUE;
1749         break; // complete the irp
1750     }
1751 
1752     case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME:
1753     {
1754         status = RequestHandleMountQueryDeviceName(deviceExtension, Request, RequestParameters, &dataLength);
1755 
1756         processed = TRUE;
1757         break; // complete the irp
1758     }
1759 
1760     case IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME:
1761     {
1762         status = RequestHandleMountQuerySuggestedLinkName(deviceExtension, Request, RequestParameters, &dataLength);
1763 
1764         processed = TRUE;
1765         break; // complete the irp
1766     }
1767 
1768     case IOCTL_STORAGE_GET_DEVICE_NUMBER:
1769     {
1770         status = RequestHandleGetDeviceNumber(deviceExtension, Request, RequestParameters, &dataLength);
1771 
1772         processed = TRUE;
1773         break; // complete the irp
1774     }
1775 
1776     case IOCTL_STORAGE_GET_HOTPLUG_INFO:
1777     {
1778         status = RequestHandleGetHotPlugInfo(deviceExtension, Request, RequestParameters, &dataLength);
1779 
1780         processed = TRUE;
1781         break; // complete the irp
1782     }
1783 
1784     case IOCTL_STORAGE_SET_HOTPLUG_INFO:
1785     {
1786         status = RequestHandleSetHotPlugInfo(deviceExtension, Request, RequestParameters, &dataLength);
1787 
1788         processed = TRUE;
1789         break; // complete the irp
1790     }
1791 
1792     case IOCTL_STORAGE_EVENT_NOTIFICATION:
1793     {
1794         status = RequestHandleEventNotification(deviceExtension, Request, &RequestParameters, &dataLength);
1795 
1796         processed = TRUE;
1797         break; // complete the irp
1798     }
1799 
1800 #if (NTDDI_VERSION >= NTDDI_WIN8)
1801     case IOCTL_VOLUME_ONLINE:
1802     {
1803         //
1804         // Mount manager and volume manager will
1805         // follow this online with a post online
1806         // but other callers may not. In those
1807         // cases, we process this request right
1808         // away. We approximate that these other
1809         // callers are from user mode
1810         //
1811 
1812         if (WdfRequestGetRequestorMode(Request) == KernelMode)
1813         {
1814             processed = TRUE;
1815         }
1816         break;
1817     }
1818 #endif
1819 
1820     default:
1821     {
1822         processed = FALSE;
1823         break;
1824     }
1825 
1826     } //end of switch (ioctlCode)
1827 
1828     if (processed)
1829     {
1830         UCHAR currentStackLocationFlags = 0;
1831         currentStackLocationFlags = RequestGetCurrentStackLocationFlags(Request);
1832 
1833         if ((status == STATUS_VERIFY_REQUIRED) &&
1834             (currentStackLocationFlags & SL_OVERRIDE_VERIFY_VOLUME))
1835         {
1836             // If the status is verified required and this request
1837             // should bypass verify required then retry the request.
1838             status = STATUS_IO_DEVICE_ERROR;
1839             UNREFERENCED_PARAMETER(status); // disables prefast warning; defensive coding...
1840 
1841             processed = RequestDispatchProcessDirectly(Device, Request, RequestParameters);
1842         }
1843         else
1844         {
1845             // Complete the request after processing it.
1846             RequestCompletion(deviceExtension, Request, status, dataLength);
1847         }
1848     }
1849 
1850     return processed;
1851 }
1852 
1853 
1854 BOOLEAN
RequestDispatchToSequentialQueue(_In_ WDFDEVICE Device,_In_ WDFREQUEST Request,_In_ WDF_REQUEST_PARAMETERS RequestParameters)1855 RequestDispatchToSequentialQueue(
1856     _In_ WDFDEVICE              Device,
1857     _In_ WDFREQUEST             Request,
1858     _In_ WDF_REQUEST_PARAMETERS RequestParameters
1859     )
1860 /*++
1861 Routine Description:
1862 
1863     These requests can be processed in a non-serialized manner, most of them don't need to access device.
1864 
1865 Arguments:
1866 
1867     Device - handle to a WDF Device object
1868 
1869     Request - handle to the incoming WDF Request object
1870 
1871     RequestParameters - request parameters
1872 
1873 Return Value:
1874 
1875     BOOLEAN - TRUE (request processed); FALSE (request is not processed in this function).
1876 
1877 --*/
1878 {
1879     NTSTATUS                status = STATUS_SUCCESS;
1880     BOOLEAN                 processed = FALSE;
1881     size_t                  dataLength = 0;
1882     BOOLEAN                 inZeroPowerState = FALSE;
1883 
1884     PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device);
1885     ULONG                   ioctlCode = RequestParameters.Parameters.DeviceIoControl.IoControlCode;
1886     PZERO_POWER_ODD_INFO    zpoddInfo = deviceExtension->ZeroPowerODDInfo;
1887 
1888     if ((zpoddInfo != NULL) &&
1889         (zpoddInfo->InZeroPowerState != FALSE))
1890     {
1891         inZeroPowerState = TRUE;
1892     }
1893 
1894     switch (ioctlCode)
1895     {
1896 
1897     case IOCTL_CDROM_RAW_READ:
1898     {
1899         status = RequestValidateRawRead(deviceExtension, Request, RequestParameters, &dataLength);
1900 
1901         processed = TRUE;
1902         break;
1903     }
1904 
1905     case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX:
1906     case IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX:
1907     {
1908         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
1909                     "RequestDispatchToSequentialQueue: Get drive geometryEx\n"));
1910         if ( RequestParameters.Parameters.DeviceIoControl.OutputBufferLength <
1911              (ULONG)FIELD_OFFSET(DISK_GEOMETRY_EX, Data))
1912         {
1913             status = STATUS_BUFFER_TOO_SMALL;
1914             dataLength = FIELD_OFFSET(DISK_GEOMETRY_EX, Data);
1915         }
1916         else if (inZeroPowerState != FALSE)
1917         {
1918             status = STATUS_NO_MEDIA_IN_DEVICE;
1919         }
1920         else
1921         {
1922             status = STATUS_SUCCESS;
1923         }
1924 
1925         processed = TRUE;
1926         break;
1927     }
1928 
1929     case IOCTL_DISK_GET_DRIVE_GEOMETRY:
1930     case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
1931     {
1932         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
1933                     "RequestDispatchToSequentialQueue: Get drive geometry\n"));
1934         if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength <
1935             sizeof(DISK_GEOMETRY))
1936         {
1937             status = STATUS_BUFFER_TOO_SMALL;
1938             dataLength = sizeof(DISK_GEOMETRY);
1939         }
1940         else if (inZeroPowerState != FALSE)
1941         {
1942             status = STATUS_NO_MEDIA_IN_DEVICE;
1943         }
1944         else
1945         {
1946             status = STATUS_SUCCESS;
1947         }
1948 
1949         processed = TRUE;
1950         break;
1951     }
1952 
1953     case IOCTL_CDROM_READ_TOC_EX:
1954     {
1955         status = RequestValidateReadTocEx(deviceExtension, Request, RequestParameters, &dataLength);
1956 
1957         if (inZeroPowerState != FALSE)
1958         {
1959             status = STATUS_NO_MEDIA_IN_DEVICE;
1960         }
1961 
1962         processed = TRUE;
1963         break;
1964     }
1965 
1966     case IOCTL_CDROM_READ_TOC:
1967     {
1968         status = RequestValidateReadToc(deviceExtension, RequestParameters, &dataLength);
1969 
1970         if (inZeroPowerState != FALSE)
1971         {
1972             status = STATUS_NO_MEDIA_IN_DEVICE;
1973         }
1974 
1975         processed = TRUE;
1976         break;
1977     }
1978 
1979     case IOCTL_CDROM_GET_LAST_SESSION:
1980     {
1981         status = RequestValidateGetLastSession(deviceExtension, RequestParameters, &dataLength);
1982 
1983         processed = TRUE;
1984         break;
1985     }
1986 
1987     case IOCTL_CDROM_PLAY_AUDIO_MSF:
1988     {
1989         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
1990                     "RequestDispatchToSequentialQueue: Play audio MSF\n"));
1991 
1992         if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength <
1993             sizeof(CDROM_PLAY_AUDIO_MSF))
1994         {
1995             status = STATUS_INFO_LENGTH_MISMATCH;
1996         }
1997         else
1998         {
1999             status = STATUS_SUCCESS;
2000         }
2001 
2002         processed = TRUE;
2003         break;
2004     }
2005 
2006     case IOCTL_CDROM_SEEK_AUDIO_MSF:
2007     {
2008         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2009                     "RequestDispatchToSequentialQueue: Seek audio MSF\n"));
2010 
2011         if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength <
2012             sizeof(CDROM_SEEK_AUDIO_MSF))
2013         {
2014             status = STATUS_INFO_LENGTH_MISMATCH;
2015         }
2016         else
2017         {
2018             status = STATUS_SUCCESS;
2019         }
2020 
2021         processed = TRUE;
2022         break;
2023     }
2024 
2025     case IOCTL_CDROM_PAUSE_AUDIO:
2026     {
2027         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2028                     "RequestDispatchToSequentialQueue: Pause audio\n"));
2029 
2030         status = STATUS_SUCCESS;
2031         processed = TRUE;
2032         break;
2033     }
2034 
2035     case IOCTL_CDROM_RESUME_AUDIO:
2036     {
2037         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2038                     "RequestDispatchToSequentialQueue: Resume audio\n"));
2039 
2040         status = STATUS_SUCCESS;
2041         processed = TRUE;
2042         break;
2043     }
2044 
2045     case IOCTL_CDROM_READ_Q_CHANNEL:
2046     {
2047         status = RequestValidateReadQChannel(Request, RequestParameters, &dataLength);
2048 
2049         processed = TRUE;
2050         break;
2051     }
2052 
2053     case IOCTL_CDROM_GET_VOLUME:
2054     {
2055         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2056                     "RequestDispatchToSequentialQueue: Get volume control\n"));
2057 
2058         if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength <
2059             sizeof(VOLUME_CONTROL))
2060         {
2061             status = STATUS_BUFFER_TOO_SMALL;
2062             dataLength = sizeof(VOLUME_CONTROL);
2063         }
2064         else
2065         {
2066             status = STATUS_SUCCESS;
2067         }
2068 
2069         processed = TRUE;
2070         break;
2071     }
2072 
2073     case IOCTL_CDROM_SET_VOLUME:
2074     {
2075         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2076                     "RequestDispatchToSequentialQueue: Set volume control\n"));
2077 
2078         if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength <
2079             sizeof(VOLUME_CONTROL))
2080         {
2081             status = STATUS_INFO_LENGTH_MISMATCH;
2082         }
2083         else
2084         {
2085             status = STATUS_SUCCESS;
2086         }
2087 
2088         processed = TRUE;
2089         break;
2090     }
2091 
2092     case IOCTL_CDROM_STOP_AUDIO:
2093     {
2094         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2095                     "RequestDispatchToSequentialQueue: Stop audio\n"));
2096 
2097         status = STATUS_SUCCESS;
2098         processed = TRUE;
2099         break;
2100     }
2101 
2102     case IOCTL_STORAGE_CHECK_VERIFY:
2103     case IOCTL_STORAGE_CHECK_VERIFY2:
2104     {
2105         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2106                     "RequestDispatchToSequentialQueue: [%p] Check Verify\n", Request));
2107 
2108         // Following check will let the condition "OutputBufferLength == 0" pass.
2109         // Since it's legacy behavior in classpnp, we need to keep it.
2110         if ((RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > 0) &&
2111             (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)))
2112         {
2113             status = STATUS_BUFFER_TOO_SMALL;
2114             dataLength = sizeof(ULONG);
2115         }
2116         else if (inZeroPowerState != FALSE)
2117         {
2118             status = STATUS_NO_MEDIA_IN_DEVICE;
2119         }
2120         else
2121         {
2122             status = STATUS_SUCCESS;
2123         }
2124 
2125         processed = TRUE;
2126         break;
2127     }
2128 
2129     case IOCTL_DVD_GET_REGION:
2130     {
2131         // validation will be done when process it.
2132         status = STATUS_SUCCESS;
2133         processed = TRUE;
2134         break;
2135     }
2136 
2137     case IOCTL_DVD_READ_STRUCTURE:
2138     {
2139         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2140                     "RequestDispatchToSequentialQueue: [%p] IOCTL_DVD_READ_STRUCTURE\n", Request));
2141 
2142         status = RequestValidateDvdReadStructure(deviceExtension, RequestParameters, &dataLength);
2143 
2144         processed = TRUE;
2145         break;
2146     }
2147 
2148     case IOCTL_DVD_READ_KEY:
2149     {
2150         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2151                     "RequestDispatchToSequentialQueue: [%p] IOCTL_DVD_READ_KEY\n", Request));
2152 
2153         status = RequestValidateDvdReadKey(deviceExtension, Request, RequestParameters, &dataLength);
2154 
2155         processed = TRUE;
2156         break;
2157     }
2158 
2159     case IOCTL_DVD_START_SESSION:
2160     {
2161         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2162                     "RequestDispatchToSequentialQueue: [%p] IOCTL_DVD_START_SESSION\n", Request));
2163 
2164         status = RequestValidateDvdStartSession(deviceExtension, RequestParameters, &dataLength);
2165 
2166         processed = TRUE;
2167         break;
2168     }
2169 
2170     case IOCTL_DVD_SEND_KEY:
2171     case IOCTL_DVD_SEND_KEY2:
2172     {
2173         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2174                     "RequestDispatchToSequentialQueue: [%p] IOCTL_DVD_SEND_KEY\n", Request));
2175 
2176         status = RequestValidateDvdSendKey(deviceExtension, Request, RequestParameters, &dataLength);
2177 
2178         processed = TRUE;
2179         break;
2180     }
2181 
2182     case IOCTL_STORAGE_SET_READ_AHEAD:
2183     {
2184         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2185                     "RequestDispatchToSequentialQueue: [%p] SetReadAhead\n", Request));
2186 
2187         if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength <
2188             sizeof(STORAGE_SET_READ_AHEAD))
2189         {
2190             status = STATUS_INVALID_PARAMETER;
2191         }
2192         else
2193         {
2194             status = STATUS_SUCCESS;
2195         }
2196 
2197         processed = TRUE;
2198         break;
2199     }
2200 
2201     case IOCTL_DISK_IS_WRITABLE:
2202     {
2203         status = STATUS_SUCCESS;
2204 
2205         processed = TRUE;
2206         break;
2207     }
2208 
2209     case IOCTL_DISK_GET_DRIVE_LAYOUT:
2210     {
2211         ULONG requiredSize = 0;
2212 
2213         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2214                     "RequestDispatchToSequentialQueue: Get drive layout\n"));
2215 
2216         requiredSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION, PartitionEntry[1]);
2217 
2218         if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength <
2219             requiredSize)
2220         {
2221             status = STATUS_BUFFER_TOO_SMALL;
2222             dataLength = requiredSize;
2223         }
2224         else
2225         {
2226             status = STATUS_SUCCESS;
2227         }
2228 
2229         processed = TRUE;
2230         break;
2231     }
2232 
2233     case IOCTL_DISK_GET_DRIVE_LAYOUT_EX:
2234     {
2235         ULONG requiredSize = 0;
2236 
2237         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2238                     "RequestDispatchToSequentialQueue: Get drive layoutEx\n"));
2239 
2240         requiredSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[1]);
2241 
2242         if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength <
2243             requiredSize)
2244         {
2245             status = STATUS_BUFFER_TOO_SMALL;
2246             dataLength = requiredSize;
2247         }
2248         else
2249         {
2250             status = STATUS_SUCCESS;
2251         }
2252 
2253         processed = TRUE;
2254         break;
2255     }
2256 
2257     case IOCTL_DISK_GET_PARTITION_INFO:
2258     {
2259         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2260                     "RequestDispatchToSequentialQueue: Get Partition Info\n"));
2261 
2262         if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength <
2263             sizeof(PARTITION_INFORMATION))
2264         {
2265             status = STATUS_BUFFER_TOO_SMALL;
2266             dataLength = sizeof(PARTITION_INFORMATION);
2267         }
2268         else
2269         {
2270             status = STATUS_SUCCESS;
2271         }
2272 
2273         processed = TRUE;
2274         break;
2275     }
2276 
2277     case IOCTL_DISK_GET_PARTITION_INFO_EX:
2278     {
2279         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2280                     "RequestDispatchToSequentialQueue: Get Partition InfoEx\n"));
2281 
2282         if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength <
2283             sizeof(PARTITION_INFORMATION_EX))
2284         {
2285             status = STATUS_BUFFER_TOO_SMALL;
2286             dataLength = sizeof(PARTITION_INFORMATION_EX);
2287         }
2288         else
2289         {
2290             status = STATUS_SUCCESS;
2291         }
2292 
2293         processed = TRUE;
2294         break;
2295     }
2296 
2297     case IOCTL_DISK_VERIFY:
2298     {
2299         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2300                     "RequestDispatchToSequentialQueue: IOCTL_DISK_VERIFY to device %p through request %p\n",
2301                     Device,
2302                     Request));
2303 
2304         if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength <
2305             sizeof(VERIFY_INFORMATION))
2306         {
2307             status = STATUS_INVALID_PARAMETER;
2308         }
2309         else
2310         {
2311             status = STATUS_SUCCESS;
2312         }
2313 
2314         processed = TRUE;
2315         break;
2316     }
2317 
2318     case IOCTL_DISK_GET_LENGTH_INFO:
2319     {
2320         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2321                     "RequestDispatchToSequentialQueue: Disk Get Length InfoEx\n"));
2322 
2323         if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength <
2324             sizeof(GET_LENGTH_INFORMATION))
2325         {
2326             status = STATUS_BUFFER_TOO_SMALL;
2327             dataLength = sizeof(GET_LENGTH_INFORMATION);
2328         }
2329         else if (inZeroPowerState != FALSE)
2330         {
2331             status = STATUS_NO_MEDIA_IN_DEVICE;
2332         }
2333         else
2334         {
2335             status = STATUS_SUCCESS;
2336         }
2337 
2338         processed = TRUE;
2339         break;
2340     }
2341 
2342     case IOCTL_CDROM_GET_CONFIGURATION:
2343     {
2344         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2345                     "RequestDispatchToSequentialQueue: [%p] IOCTL_CDROM_GET_CONFIGURATION\n", Request));
2346 
2347         status = RequestValidateGetConfiguration(deviceExtension, Request, RequestParameters, &dataLength);
2348 
2349         processed = TRUE;
2350         break;
2351     }
2352 
2353     case IOCTL_CDROM_SET_SPEED:
2354     {
2355         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2356                     "RequestDispatchToSequentialQueue: [%p] IOCTL_CDROM_SET_SPEED\n", Request));
2357 
2358         status = RequestValidateSetSpeed(deviceExtension, Request, RequestParameters, &dataLength);
2359 
2360         processed = TRUE;
2361         break;
2362     }
2363 
2364     case IOCTL_DVD_END_SESSION:
2365     {
2366         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2367                     "RequestDispatchToSequentialQueue: [%p] IOCTL_DVD_END_SESSION\n", Request));
2368 
2369         status = RequestValidateDvdEndSession(deviceExtension, Request, RequestParameters, &dataLength);
2370 
2371         processed = TRUE;
2372         break;
2373     }
2374 
2375     case IOCTL_AACS_END_SESSION:
2376     {
2377         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2378                     "RequestDispatchToSequentialQueue: [%p] IOCTL_AACS_END_SESSION\n", Request));
2379 
2380         status = RequestValidateAacsEndSession(deviceExtension, Request, RequestParameters, &dataLength);
2381 
2382         processed = TRUE;
2383         break;
2384     }
2385 
2386     case IOCTL_AACS_READ_MEDIA_KEY_BLOCK:
2387     {
2388         TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
2389                     "AACS: Querying full MKB with bufferSize of %x bytes\n",
2390                     (int)RequestParameters.Parameters.DeviceIoControl.OutputBufferLength
2391                     ));
2392 
2393         status = RequestValidateAacsReadMediaKeyBlock(deviceExtension, Request, RequestParameters, &dataLength);
2394 
2395         processed = TRUE;
2396         break;
2397     }
2398 
2399     case IOCTL_AACS_START_SESSION:
2400     {
2401         TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
2402                     "AACS: Requesting AGID\n"
2403                     ));
2404 
2405         status = RequestValidateAacsStartSession(deviceExtension, RequestParameters, &dataLength);
2406 
2407         processed = TRUE;
2408         break;
2409     }
2410 
2411     case IOCTL_AACS_SEND_CERTIFICATE:
2412     {
2413         TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
2414                     "AACS: Sending host certificate to drive\n"
2415                     ));
2416 
2417         status = RequestValidateAacsSendCertificate(deviceExtension, Request, RequestParameters, &dataLength);
2418 
2419         processed = TRUE;
2420         break;
2421     }
2422 
2423     case IOCTL_AACS_GET_CERTIFICATE:
2424     {
2425         TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
2426                     "AACS: Querying drive certificate\n"
2427                     ));
2428 
2429         status = RequestValidateAacsGetCertificate(deviceExtension, Request, RequestParameters, &dataLength);
2430 
2431         processed = TRUE;
2432         break;
2433     }
2434 
2435     case IOCTL_AACS_GET_CHALLENGE_KEY:
2436     {
2437         TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
2438                     "AACS: Querying drive challenge key\n"
2439                     ));
2440 
2441         status = RequestValidateAacsGetChallengeKey(deviceExtension, Request, RequestParameters, &dataLength);
2442 
2443         processed = TRUE;
2444         break;
2445     }
2446 
2447     case IOCTL_AACS_SEND_CHALLENGE_KEY:
2448     {
2449         TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
2450                     "AACS: Sending drive challenge key\n"
2451                     ));
2452 
2453         status = RequestValidateAacsSendChallengeKey(deviceExtension, Request, RequestParameters, &dataLength);
2454 
2455         processed = TRUE;
2456         break;
2457     }
2458 
2459     case IOCTL_AACS_READ_VOLUME_ID:
2460     {
2461         TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
2462                     "AACS: Reading volume ID\n"
2463                     ));
2464 
2465         status = RequestValidateAacsReadVolumeId(deviceExtension, Request, RequestParameters, &dataLength);
2466 
2467         processed = TRUE;
2468         break;
2469     }
2470 
2471     case IOCTL_AACS_READ_SERIAL_NUMBER:
2472     {
2473         TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
2474                     "AACS: Reading Serial Number\n"
2475                     ));
2476 
2477         status = RequestValidateAacsReadSerialNumber(deviceExtension, Request, RequestParameters, &dataLength);
2478 
2479         processed = TRUE;
2480         break;
2481     }
2482 
2483     case IOCTL_AACS_READ_MEDIA_ID:
2484     {
2485         TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
2486                     "AACS: Reading media ID\n"
2487                     ));
2488 
2489         status = RequestValidateAacsReadMediaId(deviceExtension, Request, RequestParameters, &dataLength);
2490 
2491         processed = TRUE;
2492         break;
2493     }
2494 
2495     case IOCTL_AACS_READ_BINDING_NONCE:
2496     case IOCTL_AACS_GENERATE_BINDING_NONCE:
2497     {
2498         if (ioctlCode == IOCTL_AACS_GENERATE_BINDING_NONCE)
2499         {
2500             TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
2501                         "AACS: Generating new binding nonce\n"
2502                         ));
2503         }
2504         else
2505         {
2506             TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
2507                         "AACS: Reading existing binding nonce\n"
2508                         ));
2509         }
2510 
2511         status = RequestValidateAacsBindingNonce(deviceExtension, Request, RequestParameters, &dataLength);
2512 
2513         processed = TRUE;
2514         break;
2515     }
2516 
2517     case IOCTL_CDROM_ENABLE_STREAMING:
2518     {
2519         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2520                     "RequestDispatchToSequentialQueue: [%p] IOCTL_CDROM_ENABLE_STREAMING\n", Request));
2521 
2522         status = RequestValidateEnableStreaming(Request, RequestParameters, &dataLength);
2523 
2524         processed = TRUE;
2525         break;
2526     }
2527 
2528     case IOCTL_CDROM_SEND_OPC_INFORMATION:
2529     {
2530         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2531                     "RequestDispatchToSequentialQueue: [%p] IOCTL_CDROM_SEND_OPC_INFORMATION\n", Request));
2532 
2533         status = RequestValidateSendOpcInformation(Request, RequestParameters, &dataLength);
2534 
2535         processed = TRUE;
2536         break;
2537     }
2538 
2539     case IOCTL_CDROM_GET_PERFORMANCE:
2540     {
2541         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2542                     "RequestDispatchToSequentialQueue: [%p] IOCTL_CDROM_GET_PERFORMANCE\n", Request));
2543 
2544         status = RequestValidateGetPerformance(Request, RequestParameters, &dataLength);
2545 
2546         processed = TRUE;
2547         break;
2548     }
2549 
2550     case IOCTL_STORAGE_MEDIA_REMOVAL:
2551     case IOCTL_STORAGE_EJECTION_CONTROL:
2552     {
2553         if(RequestParameters.Parameters.DeviceIoControl.InputBufferLength <
2554            sizeof(PREVENT_MEDIA_REMOVAL))
2555         {
2556             status = STATUS_INFO_LENGTH_MISMATCH;
2557         }
2558         else
2559         {
2560             status = STATUS_SUCCESS;
2561         }
2562 
2563         processed = TRUE;
2564         break; // complete the irp
2565     }
2566 
2567     case IOCTL_STORAGE_MCN_CONTROL:
2568     {
2569         if(RequestParameters.Parameters.DeviceIoControl.InputBufferLength <
2570             sizeof(PREVENT_MEDIA_REMOVAL))
2571         {
2572             status = STATUS_INFO_LENGTH_MISMATCH;
2573         }
2574         else
2575         {
2576             status = STATUS_SUCCESS;
2577         }
2578 
2579         processed = TRUE;
2580         break; // complete the irp
2581     }
2582 
2583     case IOCTL_STORAGE_RESERVE:
2584     case IOCTL_STORAGE_RELEASE:
2585     {
2586         // there is no validate check currently.
2587         status = STATUS_SUCCESS;
2588         processed = TRUE;
2589         break;
2590     }
2591 
2592     case IOCTL_STORAGE_PERSISTENT_RESERVE_IN:
2593     case IOCTL_STORAGE_PERSISTENT_RESERVE_OUT:
2594     {
2595         status = RequestValidatePersistentReserve(deviceExtension, Request, RequestParameters, &dataLength);
2596 
2597         processed = TRUE;
2598         break;
2599     }
2600 
2601     case IOCTL_STORAGE_EJECT_MEDIA:
2602     case IOCTL_STORAGE_LOAD_MEDIA:
2603     case IOCTL_STORAGE_LOAD_MEDIA2:
2604     {
2605         status = STATUS_SUCCESS;
2606 
2607         processed = TRUE;
2608         break; // complete the irp
2609     }
2610 
2611     case IOCTL_STORAGE_FIND_NEW_DEVICES:
2612     {
2613         // process it.
2614         IoInvalidateDeviceRelations(deviceExtension->LowerPdo, BusRelations);
2615 
2616         status = STATUS_SUCCESS;
2617 
2618         processed = TRUE;
2619         break; // complete the irp
2620     }
2621 
2622     case IOCTL_STORAGE_READ_CAPACITY:
2623     {
2624         if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(STORAGE_READ_CAPACITY))
2625         {
2626             dataLength = sizeof(STORAGE_READ_CAPACITY);
2627             status = STATUS_BUFFER_TOO_SMALL;
2628         }
2629         else if (inZeroPowerState != FALSE)
2630         {
2631             status = STATUS_NO_MEDIA_IN_DEVICE;
2632         }
2633         else
2634         {
2635             status = STATUS_SUCCESS;
2636         }
2637 
2638         processed = TRUE;
2639         break; // complete the irp
2640     }
2641 
2642     case IOCTL_STORAGE_CHECK_PRIORITY_HINT_SUPPORT:
2643     {
2644         // for disk.sys only in original classpnp
2645         status = STATUS_NOT_SUPPORTED;
2646 
2647         processed = TRUE;
2648         break; // complete the irp
2649     }
2650 
2651 #if (NTDDI_VERSION >= NTDDI_WIN8)
2652     case IOCTL_DISK_ARE_VOLUMES_READY:
2653     {
2654         // this request doesn't access device at all, so seemingly it can be processed
2655         // directly; however, in case volume online is not received, we will need to
2656         // park these requests in a queue, and the only way a request can be queued is
2657         // if the request came out of another queue.
2658         status = STATUS_SUCCESS;
2659 
2660         processed = TRUE;
2661         break;
2662     }
2663 
2664     case IOCTL_VOLUME_ONLINE:
2665     case IOCTL_VOLUME_POST_ONLINE:
2666     {
2667         status = STATUS_SUCCESS;
2668 
2669         processed = TRUE;
2670         break;
2671     }
2672 #endif
2673 
2674     default:
2675     {
2676         processed = FALSE;
2677         break;
2678     }
2679     } //end of switch (ioctlCode)
2680 
2681     if (processed)
2682     {
2683         UCHAR currentStackLocationFlags = 0;
2684         currentStackLocationFlags = RequestGetCurrentStackLocationFlags(Request);
2685 
2686         if ((status == STATUS_VERIFY_REQUIRED) &&
2687             (currentStackLocationFlags & SL_OVERRIDE_VERIFY_VOLUME))
2688         {
2689             // If the status is verified required and this request
2690             // should bypass verify required then retry the request.
2691             status = STATUS_IO_DEVICE_ERROR;
2692             UNREFERENCED_PARAMETER(status); // disables prefast warning; defensive coding...
2693 
2694             processed = RequestDispatchToSequentialQueue(Device, Request, RequestParameters);
2695         }
2696         else
2697         {
2698             if (NT_SUCCESS(status))
2699             {
2700                 // Forward the request to serialized queue.
2701                 status = WdfDeviceEnqueueRequest(Device, Request);
2702             }
2703 
2704             if (!NT_SUCCESS(status))
2705             {
2706                 // Validation failed / forward failed, complete the request.
2707                 RequestCompletion(deviceExtension, Request, status, dataLength);
2708             }
2709         }
2710     }
2711 
2712     return processed;
2713 }
2714 
2715 
2716 BOOLEAN
RequestDispatchSyncWithSequentialQueue(_In_ WDFDEVICE Device,_In_ WDFREQUEST Request,_In_ WDF_REQUEST_PARAMETERS RequestParameters)2717 RequestDispatchSyncWithSequentialQueue(
2718     _In_ WDFDEVICE              Device,
2719     _In_ WDFREQUEST             Request,
2720     _In_ WDF_REQUEST_PARAMETERS RequestParameters
2721     )
2722 /*++
2723 Routine Description:
2724 
2725     These requests need to stay in caller's context and be processed in serialized manner.
2726 
2727 Arguments:
2728 
2729     Device - handle to a WDF Device object
2730 
2731     Request - handle to the incoming WDF Request object
2732 
2733     RequestParameters - request parameters
2734 
2735 Return Value:
2736 
2737     BOOLEAN - TRUE (request processed); FALSE (request is not processed in this function).
2738 
2739 --*/
2740 {
2741     NTSTATUS                status = STATUS_SUCCESS;
2742     BOOLEAN                 processed = FALSE;
2743     size_t                  dataLength = 0;
2744 
2745     PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device);
2746     ULONG                   ioctlCode = RequestParameters.Parameters.DeviceIoControl.IoControlCode;
2747 
2748     switch (ioctlCode)
2749     {
2750 
2751     case IOCTL_CDROM_EXCLUSIVE_ACCESS:
2752     {
2753         //1. Validate
2754         status =  RequestValidateExclusiveAccess(Request, RequestParameters, &dataLength);
2755 
2756         //2. keep the request in serialized manner and stay in user's context.
2757         if (NT_SUCCESS(status))
2758         {
2759             PCDROM_EXCLUSIVE_ACCESS exclusiveAccess = NULL;
2760 
2761             status = WdfRequestRetrieveInputBuffer(Request,
2762                                                    RequestParameters.Parameters.DeviceIoControl.InputBufferLength,
2763                                                    &exclusiveAccess,
2764                                                    NULL);
2765 
2766             if (NT_SUCCESS(status))
2767             {
2768                 // do not need to check "status" as it passed validation and cannot fail in WdfRequestRetrieveInputBuffer()
2769                 switch (exclusiveAccess->RequestType)
2770                 {
2771 
2772                     case ExclusiveAccessQueryState:
2773                     {
2774                         status = RequestSetContextFields(Request, RequestHandleExclusiveAccessQueryLockState);
2775                         break;
2776                     }
2777 
2778                     case ExclusiveAccessLockDevice:
2779                     {
2780                         status = RequestSetContextFields(Request, RequestHandleExclusiveAccessLockDevice);
2781                         break;
2782                     }
2783 
2784                     case ExclusiveAccessUnlockDevice:
2785                     {
2786                         status = RequestSetContextFields(Request, RequestHandleExclusiveAccessUnlockDevice);
2787                         break;
2788                     }
2789                     default:
2790                     {
2791                         // already valicated in RequestValidateExclusiveAccess()
2792                         NT_ASSERT(FALSE);
2793                         break;
2794                     }
2795                 }
2796             }
2797 
2798             if (NT_SUCCESS(status))
2799             {
2800                 // now, put the special synchronization information into the context
2801                 status = RequestSynchronizeProcessWithSerialQueue(Device, Request);
2802 
2803                 // "status" is used for debugging in above statement, reset to success to avoid further work in this function.
2804                 status = STATUS_SUCCESS;
2805             }
2806         }
2807 
2808         processed = TRUE;
2809         break; // complete the irp
2810     }
2811 
2812     default:
2813     {
2814         processed = FALSE;
2815         break;
2816     }
2817     } //end of switch (ioctlCode)
2818 
2819     // Following process is only valid if the request is not really processed. (failed in validation)
2820     if (processed && !NT_SUCCESS(status))
2821     {
2822         UCHAR currentStackLocationFlags = 0;
2823         currentStackLocationFlags = RequestGetCurrentStackLocationFlags(Request);
2824 
2825         if ((status == STATUS_VERIFY_REQUIRED) &&
2826             (currentStackLocationFlags & SL_OVERRIDE_VERIFY_VOLUME))
2827         {
2828             //
2829             // If the status is verified required and this request
2830             // should bypass verify required then retry the request.
2831             //
2832             status = STATUS_IO_DEVICE_ERROR;
2833             UNREFERENCED_PARAMETER(status); // disables prefast warning; defensive coding...
2834 
2835             processed = RequestDispatchSyncWithSequentialQueue(Device, Request, RequestParameters);
2836         }
2837         else
2838         {
2839             // Validation failed / forward failed, complete the request.
2840             RequestCompletion(deviceExtension, Request, status, dataLength);
2841         }
2842     }
2843 
2844     return processed;
2845 }
2846 
2847 
2848 BOOLEAN
RequestDispatchSpecialIoctls(_In_ WDFDEVICE Device,_In_ WDFREQUEST Request,_In_ WDF_REQUEST_PARAMETERS RequestParameters)2849 RequestDispatchSpecialIoctls(
2850     _In_ WDFDEVICE              Device,
2851     _In_ WDFREQUEST             Request,
2852     _In_ WDF_REQUEST_PARAMETERS RequestParameters
2853     )
2854 /*++
2855 Routine Description:
2856 
2857     These requests need to be processed in different manner according to input parameters
2858 
2859 Arguments:
2860 
2861     Device - handle to a WDF Device object
2862 
2863     Request - handle to the incoming WDF Request object
2864 
2865     RequestParameters - request parameters
2866 
2867 Return Value:
2868 
2869     BOOLEAN - TRUE (request processed); FALSE (request is not processed in this function).
2870 
2871 --*/
2872 {
2873     NTSTATUS                status = STATUS_SUCCESS;
2874     BOOLEAN                 processed = FALSE;
2875     size_t                  dataLength = 0;
2876     BOOLEAN                 requestCompleted = FALSE;
2877 
2878     PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device);
2879     PCDROM_DATA             cdData = &(deviceExtension->DeviceAdditionalData);
2880     ULONG                   ioctlCode = RequestParameters.Parameters.DeviceIoControl.IoControlCode;
2881 
2882     switch (ioctlCode)
2883     {
2884     case IOCTL_SCSI_PASS_THROUGH:
2885     case IOCTL_SCSI_PASS_THROUGH_DIRECT:
2886     case IOCTL_SCSI_PASS_THROUGH_EX:
2887     case IOCTL_SCSI_PASS_THROUGH_DIRECT_EX:
2888     {
2889         // SPTI is considered special case as we need to set the MinorFunction before pass to low level.
2890 
2891 #if defined (_WIN64)
2892         if (WdfRequestIsFrom32BitProcess(Request))
2893         {
2894             if ((ioctlCode == IOCTL_SCSI_PASS_THROUGH) || (ioctlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT))
2895             {
2896                 if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < sizeof(SCSI_PASS_THROUGH32))
2897                 {
2898                     status = STATUS_INVALID_PARAMETER;
2899                 }
2900             }
2901             else
2902             {
2903                 if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < sizeof(SCSI_PASS_THROUGH32_EX))
2904                 {
2905                     status = STATUS_INVALID_PARAMETER;
2906                 }
2907             }
2908         }
2909         else
2910 #endif
2911         {
2912             if ((ioctlCode == IOCTL_SCSI_PASS_THROUGH) || (ioctlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT))
2913             {
2914                 if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < sizeof(SCSI_PASS_THROUGH))
2915                 {
2916                     status = STATUS_INVALID_PARAMETER;
2917                 }
2918             }
2919             else
2920             {
2921                 if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < sizeof(SCSI_PASS_THROUGH_EX))
2922                 {
2923                     status = STATUS_INVALID_PARAMETER;
2924                 }
2925             }
2926         }
2927 
2928         if (!NT_SUCCESS(status))
2929         {
2930             // validation failed.
2931             RequestCompletion(deviceExtension, Request, status, dataLength);
2932         }
2933         else
2934         {
2935             // keep the request in serialized manner and stay in user's context.
2936             status = RequestSetContextFields(Request, RequestHandleScsiPassThrough);
2937 
2938             if (NT_SUCCESS(status))
2939             {
2940                 status = RequestSynchronizeProcessWithSerialQueue(Device, Request);
2941             }
2942             else
2943             {
2944                 RequestCompletion(deviceExtension, Request, status, 0);
2945             }
2946         }
2947 
2948         requestCompleted = TRUE;
2949         processed = TRUE;
2950         break;
2951     }
2952 
2953     case IOCTL_STORAGE_QUERY_PROPERTY:
2954     {
2955         if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < sizeof(STORAGE_PROPERTY_QUERY))
2956         {
2957             status = STATUS_INFO_LENGTH_MISMATCH;
2958         }
2959         else
2960         {
2961             PSTORAGE_PROPERTY_QUERY inputBuffer = NULL;
2962 
2963             status = WdfRequestRetrieveInputBuffer(Request,
2964                                                    RequestParameters.Parameters.DeviceIoControl.InputBufferLength,
2965                                                    &inputBuffer,
2966                                                    NULL);
2967 
2968             if (NT_SUCCESS(status))
2969             {
2970                 if (!EXCLUSIVE_MODE(cdData) ||                                     // not locked
2971                     EXCLUSIVE_OWNER(cdData, WdfRequestGetFileObject(Request)) ||   // request is from lock owner
2972                     (inputBuffer->QueryType == PropertyExistsQuery))               // request not access device
2973                 {
2974                     if (inputBuffer->PropertyId == StorageDeviceUniqueIdProperty)
2975                     {
2976                         // previously handled in classpnp
2977                         // keep the request in serialized manner and stay in user's context.
2978                         status = RequestSetContextFields(Request, RequestHandleQueryPropertyDeviceUniqueId);
2979 
2980                         if (NT_SUCCESS(status))
2981                         {
2982                             status = RequestSynchronizeProcessWithSerialQueue(Device, Request);
2983                             // remeber that the request has been completed.
2984                             requestCompleted = TRUE;
2985                         }
2986                     }
2987                     else if (inputBuffer->PropertyId == StorageDeviceWriteCacheProperty)
2988                     {
2989                         // previously handled in classpnp
2990                         // keep the request in serialized manner and stay in user's context.
2991                         status = RequestSetContextFields(Request, RequestHandleQueryPropertyWriteCache);
2992 
2993                         if (NT_SUCCESS(status))
2994                         {
2995                             status = RequestSynchronizeProcessWithSerialQueue(Device, Request);
2996                             // remeber that the request has been completed.
2997                             requestCompleted = TRUE;
2998                         }
2999                     }
3000                     else
3001                     {
3002                         // Pass to port driver for handling
3003                         RequestDispatchUnknownRequests(Device, Request, RequestParameters);
3004 
3005                         // remeber that the request has been completed.
3006                         requestCompleted = TRUE;
3007                     }
3008                 }
3009                 else
3010                 {
3011                     // If cached data exists, return cached data. Otherwise, fail the request.
3012                     if ((inputBuffer->QueryType == PropertyStandardQuery) &&
3013                         ((inputBuffer->PropertyId == StorageDeviceProperty) || (inputBuffer->PropertyId == StorageAdapterProperty)) )
3014                     {
3015                         status = RequestHandleQueryPropertyRetrieveCachedData(deviceExtension, Request, RequestParameters, &dataLength);
3016                     }
3017                     else
3018                     {
3019                         status = STATUS_ACCESS_DENIED;
3020                     }
3021                 }
3022             }
3023         }
3024 
3025         processed = TRUE;
3026         break;
3027     }
3028 
3029     // this IOCTL is a fake one, used for MCN process sync-ed with serial queue.
3030     case IOCTL_MCN_SYNC_FAKE_IOCTL:
3031     {
3032         PIRP irp = WdfRequestWdmGetIrp(Request);
3033 
3034         if ((deviceExtension->MediaChangeDetectionInfo != NULL) &&
3035             (irp == deviceExtension->MediaChangeDetectionInfo->MediaChangeSyncIrp) &&
3036             (WdfRequestGetRequestorMode(Request) == KernelMode) &&
3037             (RequestParameters.Parameters.Others.Arg1 == RequestSetupMcnSyncIrp) &&
3038             (RequestParameters.Parameters.Others.Arg2 == RequestSetupMcnSyncIrp) &&
3039             (RequestParameters.Parameters.Others.Arg4 == RequestSetupMcnSyncIrp))
3040         {
3041             // This is the requset we use to sync Media Change Detection with sequential queue.
3042             status = WdfDeviceEnqueueRequest(Device, Request);
3043 
3044             if (!NT_SUCCESS(status))
3045             {
3046                 RequestCompletion(deviceExtension, Request, status, dataLength);
3047             }
3048 
3049             requestCompleted = TRUE;
3050             processed = TRUE;
3051         }
3052         else
3053         {
3054             // process as an unknown request.
3055             processed = FALSE;
3056         }
3057         break;
3058     }
3059 
3060     default:
3061     {
3062         processed = FALSE;
3063         break;
3064     }
3065     } //end of switch (ioctlCode)
3066 
3067     if (processed && !requestCompleted)
3068     {
3069         UCHAR currentStackLocationFlags = 0;
3070         currentStackLocationFlags = RequestGetCurrentStackLocationFlags(Request);
3071 
3072         if ((status == STATUS_VERIFY_REQUIRED) &&
3073             (currentStackLocationFlags & SL_OVERRIDE_VERIFY_VOLUME))
3074         {
3075             // If the status is verified required and this request
3076             // should bypass verify required then retry the request.
3077             status = STATUS_IO_DEVICE_ERROR;
3078             UNREFERENCED_PARAMETER(status); // disables prefast warning; defensive coding...
3079 
3080             processed = RequestDispatchSpecialIoctls(Device, Request, RequestParameters);
3081         }
3082         else
3083         {
3084             RequestCompletion(deviceExtension, Request, status, dataLength);
3085         }
3086     }
3087 
3088     return processed;
3089 }
3090 
3091 
3092 BOOLEAN
RequestDispatchUnknownRequests(_In_ WDFDEVICE Device,_In_ WDFREQUEST Request,_In_ WDF_REQUEST_PARAMETERS RequestParameters)3093 RequestDispatchUnknownRequests(
3094     _In_ WDFDEVICE              Device,
3095     _In_ WDFREQUEST             Request,
3096     _In_ WDF_REQUEST_PARAMETERS RequestParameters
3097     )
3098 /*++
3099 Routine Description:
3100 
3101     All unknown requests will be pass to lower level driver.
3102     If IRQL is PASSIVE_LEVEL, the request will be serialized;
3103     Otherwise, it'll be sent and forget.
3104 
3105 Arguments:
3106 
3107     Device - handle to a WDF Device object
3108 
3109     Request - handle to the incoming WDF Request object
3110 
3111     RequestParameters - request parameters
3112 
3113 Return Value:
3114 
3115     BOOLEAN - TRUE (request processed); FALSE (request is not processed in this function).
3116 
3117 --*/
3118 {
3119     NTSTATUS                status = STATUS_UNSUCCESSFUL;
3120     PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device);
3121 
3122     ULONG       baseCode = DEVICE_TYPE_FROM_CTL_CODE(RequestParameters.Parameters.DeviceIoControl.IoControlCode);
3123 
3124     if ((KeGetCurrentIrql() != PASSIVE_LEVEL) ||
3125         (baseCode == FILE_DEVICE_ACPI))
3126     {
3127         // 1. When IRQL is higher than PASSIVE_LEVEL,
3128         // 2. ataport sends IOCTL_ACPI_ASYNC_EVAL_METHOD before queue starts,
3129         // send request directly to lower driver.
3130         status = RequestHandleUnknownIoctl(Device, Request);
3131     }
3132     else
3133     {
3134         // keep the request in serialized manner and stay in user's context.
3135         status = RequestSetContextFields(Request, RequestHandleUnknownIoctl);
3136 
3137         if (NT_SUCCESS(status))
3138         {
3139             status = RequestSynchronizeProcessWithSerialQueue(Device, Request);
3140         }
3141         else
3142         {
3143             RequestCompletion(deviceExtension, Request, status, 0);
3144         }
3145     }
3146 
3147     UNREFERENCED_PARAMETER(status); //defensive coding, avoid PREFAST warning.
3148 
3149     // All unknown IOCTLs are processed in this function.
3150     return TRUE; //processed
3151 }
3152 
3153 VOID
RequestProcessInternalDeviceControl(_In_ WDFREQUEST Request,_In_ PCDROM_DEVICE_EXTENSION DeviceExtension)3154 RequestProcessInternalDeviceControl(
3155     _In_ WDFREQUEST              Request,
3156     _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
3157     )
3158 /*++
3159 Routine Description:
3160 
3161     all internal IOCTL will be send to lower driver asynchronously.
3162 
3163 Arguments:
3164 
3165     Request - handle to the incoming WDF Request object
3166     DeviceExtension - device extension structure
3167 
3168 Return Value:
3169 
3170     None
3171 
3172 --*/
3173 {
3174     NTSTATUS                 status = STATUS_SUCCESS;
3175     PIRP                     irp = NULL;
3176     PIO_STACK_LOCATION       irpStack = NULL;
3177     PIO_STACK_LOCATION       nextStack = NULL;
3178     BOOLEAN                  requestSent = FALSE;
3179 
3180     irp = WdfRequestWdmGetIrp(Request);
3181     irpStack = IoGetCurrentIrpStackLocation(irp);
3182     nextStack = IoGetNextIrpStackLocation(irp);
3183 
3184     // Set the parameters in the next stack location.
3185     nextStack->Parameters.Scsi.Srb = irpStack->Parameters.Scsi.Srb;
3186     nextStack->MajorFunction = IRP_MJ_SCSI;
3187     nextStack->MinorFunction = IRP_MN_SCSI_CLASS;
3188 
3189     WdfRequestSetCompletionRoutine(Request, RequestDummyCompletionRoutine, NULL);
3190 
3191     status = RequestSend(DeviceExtension,
3192                          Request,
3193                          DeviceExtension->IoTarget,
3194                          0,
3195                          &requestSent);
3196 
3197     // send the request straight down (asynchronously)
3198     if (!requestSent)
3199     {
3200         // fail the request
3201         RequestCompletion(DeviceExtension, Request, status, WdfRequestGetInformation(Request));
3202     }
3203 
3204     return;
3205 }
3206 
3207 
3208 
3209 //
3210 // Serial I/O Queue Event callbacks
3211 //
3212 
3213 VOID
3214 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
SequentialQueueEvtIoReadWrite(_In_ WDFQUEUE Queue,_In_ WDFREQUEST Request,_In_ size_t Length)3215 SequentialQueueEvtIoReadWrite(
3216     _In_ WDFQUEUE    Queue,
3217     _In_ WDFREQUEST  Request,
3218     _In_ size_t      Length
3219     )
3220 /*++
3221 Routine Description:
3222 
3223     validate and process read/write request.
3224 
3225 Arguments:
3226 
3227     Queue - parallel queue itself
3228 
3229     Request - handle to the incoming WDF Request object
3230 
3231     Length - read / write lenght
3232 
3233 Return Value:
3234 
3235     None
3236 
3237 --*/
3238 {
3239     NTSTATUS                status = STATUS_SUCCESS;
3240     WDFDEVICE               device = WdfIoQueueGetDevice(Queue);
3241     PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(device);
3242     WDF_REQUEST_PARAMETERS  requestParameters;
3243     PIRP                    wdmIrp = WdfRequestWdmGetIrp(Request);
3244     PIO_STACK_LOCATION      currentIrpStack = IoGetCurrentIrpStackLocation(wdmIrp);
3245     PCDROM_DATA             cdData = &(deviceExtension->DeviceAdditionalData);
3246 
3247     // Get the request parameters
3248     WDF_REQUEST_PARAMETERS_INIT(&requestParameters);
3249     WdfRequestGetParameters(Request, &requestParameters);
3250 
3251     if (requestParameters.Type ==  WdfRequestTypeRead)
3252     {
3253         TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL,
3254                     "Receiving READ, Length %Ix\n", (ULONG) Length));
3255     }
3256     else
3257     {
3258         TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL,
3259                     "Receiving WRITE, Length %Ix\n", (ULONG) Length));
3260     }
3261 
3262     // Check if a verify is required before a READ/WRITE
3263     if (TEST_FLAG(deviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME) &&
3264         (requestParameters.MinorFunction != CDROM_VOLUME_VERIFY_CHECKED) &&
3265         !TEST_FLAG(currentIrpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME))
3266     {
3267         //  DO_VERIFY_VOLUME is set for the device object,
3268         //  but this request is not itself a verify request.
3269         //  So fail this request.
3270         RequestCompletion(deviceExtension, Request, STATUS_VERIFY_REQUIRED, 0);
3271     }
3272     else
3273     {
3274         //  Since we've bypassed the verify-required tests we don't need to repeat
3275         //  them with this IRP - in particular we don't want to worry about
3276         //  hitting them at the partition 0 level if the request has come through
3277         //  a non-zero partition.
3278         currentIrpStack->MinorFunction = CDROM_VOLUME_VERIFY_CHECKED;
3279 
3280         // Fail READ/WRITE requests when music is playing
3281         if (deviceExtension->DeviceAdditionalData.PlayActive)
3282         {
3283             RequestCompletion(deviceExtension, Request, STATUS_DEVICE_BUSY, 0);
3284 
3285             return;
3286         }
3287 
3288         // Fail READ/WRITE requests from non-owners if the drive is locked
3289         if (EXCLUSIVE_MODE(cdData) && !EXCLUSIVE_OWNER(cdData, WdfRequestGetFileObject(Request)))
3290         {
3291             RequestCompletion(deviceExtension, Request, STATUS_ACCESS_DENIED, 0);
3292 
3293             return;
3294         }
3295 
3296         // Succeed READ/WRITE requests of length 0
3297         if (Length == 0)
3298         {
3299             //  Several parts of the code turn 0 into 0xffffffff,
3300             //  so don't process a zero-length request any further.
3301             RequestCompletion(deviceExtension, Request, STATUS_SUCCESS, Length);
3302 
3303             return;
3304         }
3305 
3306         // If there is an unexpected write request, we want to rediscover MMC capabilities
3307         if (!deviceExtension->DeviceAdditionalData.Mmc.WriteAllowed &&
3308             (requestParameters.Type == WdfRequestTypeWrite))
3309         {
3310             // Schedule MMC capabilities update now, but perform it later in a work item
3311             deviceExtension->DeviceAdditionalData.Mmc.UpdateState = CdromMmcUpdateRequired;
3312         }
3313 
3314         // If MMC capabilities update is required, we create a separate work item to avoid blocking
3315         // the current thread; otherwise, we initiate an async read/write in the current thread.
3316         if (DeviceIsMmcUpdateRequired(deviceExtension->Device))
3317         {
3318             deviceExtension->ReadWriteWorkItemContext.OriginalRequest = Request;
3319             WdfWorkItemEnqueue(deviceExtension->ReadWriteWorkItem);
3320 
3321             status = STATUS_SUCCESS;
3322         }
3323         else
3324         {
3325             status = RequestValidateReadWrite(deviceExtension, Request, requestParameters);
3326 
3327             if (NT_SUCCESS(status))
3328             {
3329                 status = RequestHandleReadWrite(deviceExtension, Request, requestParameters);
3330             }
3331         }
3332 
3333         if (!NT_SUCCESS(status))
3334         {
3335             RequestCompletion(deviceExtension, Request, status, 0);
3336         }
3337     }
3338 
3339     return;
3340 }
3341 
3342 
3343 VOID
3344 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
ReadWriteWorkItemRoutine(_In_ WDFWORKITEM WorkItem)3345 ReadWriteWorkItemRoutine(
3346     _In_ WDFWORKITEM  WorkItem
3347     )
3348 /*++
3349 
3350 Routine Description:
3351 
3352     Work item routine for validating and initiating read and write requests.
3353     The reason why we do that from a work item is because we may need to update MMC
3354     capabilities before validating a read/write request and that is a sync operation.
3355 
3356 Arguments:
3357 
3358     WorkItem - WDF work item
3359 
3360 Return Value:
3361 
3362     none
3363 
3364 --*/
3365 {
3366     PCDROM_DEVICE_EXTENSION             deviceExtension = NULL;
3367     WDFREQUEST                          readWriteRequest = NULL;
3368     WDF_REQUEST_PARAMETERS              readWriteRequestParameters;
3369     NTSTATUS                            status = STATUS_SUCCESS;
3370 
3371     PAGED_CODE ();
3372 
3373     deviceExtension = WdfObjectGetTypedContext(WdfWorkItemGetParentObject(WorkItem), CDROM_DEVICE_EXTENSION);
3374     readWriteRequest = deviceExtension->ReadWriteWorkItemContext.OriginalRequest;
3375     deviceExtension->ReadWriteWorkItemContext.OriginalRequest = NULL;
3376 
3377     WDF_REQUEST_PARAMETERS_INIT(&readWriteRequestParameters);
3378     WdfRequestGetParameters(readWriteRequest, &readWriteRequestParameters);
3379 
3380     if (DeviceIsMmcUpdateRequired(deviceExtension->Device))
3381     {
3382         // Issue command to update the drive capabilities.
3383         // The failure of MMC update is not considered critical, so we'll
3384         // continue to process the request even if MMC update fails.
3385         (VOID) DeviceUpdateMmcCapabilities(deviceExtension->Device);
3386     }
3387 
3388     // Now verify and process the request
3389     if (NT_SUCCESS(status))
3390     {
3391         status = RequestValidateReadWrite(deviceExtension, readWriteRequest, readWriteRequestParameters);
3392     }
3393     if (NT_SUCCESS(status))
3394     {
3395         status = RequestHandleReadWrite(deviceExtension, readWriteRequest, readWriteRequestParameters);
3396     }
3397 
3398     // Complete the request immediately on failure
3399     if (!NT_SUCCESS(status))
3400     {
3401         RequestCompletion(deviceExtension, readWriteRequest, status, 0);
3402     }
3403 }
3404 
3405 
3406 VOID
3407 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
SequentialQueueEvtIoDeviceControl(_In_ WDFQUEUE Queue,_In_ WDFREQUEST Request,_In_ size_t OutputBufferLength,_In_ size_t InputBufferLength,_In_ ULONG IoControlCode)3408 SequentialQueueEvtIoDeviceControl(
3409     _In_ WDFQUEUE   Queue,
3410     _In_ WDFREQUEST Request,
3411     _In_ size_t     OutputBufferLength,
3412     _In_ size_t     InputBufferLength,
3413     _In_ ULONG      IoControlCode
3414     )
3415 /*++
3416 Routine Description:
3417 
3418     validate and process IOCTL request.
3419 
3420 Arguments:
3421 
3422     Queue - sequential queue
3423 
3424     Request - handle to the incoming WDF Request object
3425 
3426 Return Value:
3427 
3428     None
3429 
3430 --*/
3431 {
3432     NTSTATUS                status = STATUS_SUCCESS;
3433     WDFDEVICE               device = WdfIoQueueGetDevice(Queue);
3434     PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(device);
3435     PCDROM_REQUEST_CONTEXT  requestContext = RequestGetContext(Request);
3436     PCDROM_DATA             cdData = &(deviceExtension->DeviceAdditionalData);
3437     WDF_REQUEST_PARAMETERS  requestParameters;
3438 
3439     UNREFERENCED_PARAMETER(OutputBufferLength);
3440     UNREFERENCED_PARAMETER(InputBufferLength);
3441     UNREFERENCED_PARAMETER(IoControlCode);
3442 
3443     // get the request parameters
3444     WDF_REQUEST_PARAMETERS_INIT(&requestParameters);
3445     WdfRequestGetParameters(Request, &requestParameters);
3446 
3447     // If the device is in exclusive mode, check whether the request is from
3448     // the handle that locked the device
3449     if (EXCLUSIVE_MODE(cdData) && !EXCLUSIVE_OWNER(cdData, WdfRequestGetFileObject(Request)))
3450     {
3451         BOOLEAN isBlocked = FALSE;
3452 
3453         status = RequestIsIoctlBlockedByExclusiveAccess(Request, &isBlocked);
3454         if (NT_SUCCESS(status) && isBlocked)
3455         {
3456             if (requestContext->SyncRequired)
3457             {
3458                 // set the following event, so RequestSynchronizeProcessWithSerialQueue() can contintue run to process the real request.
3459                 // this function will wait for the request process finishes.
3460                 KeSetEvent(requestContext->SyncEvent, IO_CD_ROM_INCREMENT, FALSE);
3461             }
3462             else
3463             {
3464                 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL,
3465                             "DeviceEvtIoInCallerContext: Access Denied! Device in exclusive mode.Failing Ioctl %lx\n",
3466                             requestParameters.Parameters.DeviceIoControl.IoControlCode));
3467                 RequestCompletion(deviceExtension, Request, STATUS_ACCESS_DENIED, 0);
3468             }
3469 
3470             return;
3471         }
3472     }
3473 
3474     if (!cdData->Mmc.WriteAllowed &&
3475         ((requestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_IS_WRITABLE) ||
3476          (requestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_VERIFY)))
3477     {
3478         cdData->Mmc.UpdateState = CdromMmcUpdateRequired;
3479     }
3480 
3481     // check if this is a synchronized ioctl
3482     if (requestContext->SyncRequired)
3483     {
3484         // set the following event, so RequestSynchronizeProcessWithSerialQueue() can contintue run to process the real request.
3485         // this function will wait for the request process finishes.
3486         KeSetEvent(requestContext->SyncEvent, IO_CD_ROM_INCREMENT, FALSE);
3487     }
3488     else
3489     {
3490         deviceExtension->IoctlWorkItemContext.OriginalRequest = Request;
3491 
3492         // all other IOCTL processing is currently processed via a
3493         // work item running at PASSIVE_LEVEL.
3494         WdfWorkItemEnqueue(deviceExtension->IoctlWorkItem);
3495     }
3496 
3497     return;
3498 }
3499 
3500 
3501 VOID
3502 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
IoctlWorkItemRoutine(_In_ WDFWORKITEM WorkItem)3503 IoctlWorkItemRoutine(
3504     _In_ WDFWORKITEM  WorkItem
3505     )
3506 /*++
3507 
3508 Routine Description:
3509 
3510     Work item routine for processing ioctl requests.
3511     This is needed because event callbacks are called at DISPATCH_LEVEL and ioctl
3512     requests are currently processed synchronously and not asynchronously.
3513 
3514 Arguments:
3515 
3516     WorkItem - WDF work item
3517 
3518 Return Value:
3519 
3520     none
3521 
3522 --*/
3523 {
3524     PCDROM_DEVICE_EXTENSION             deviceExtension = NULL;
3525 
3526     PAGED_CODE ();
3527 
3528     deviceExtension = WdfObjectGetTypedContext(WdfWorkItemGetParentObject(WorkItem), CDROM_DEVICE_EXTENSION);
3529 
3530     if (DeviceIsMmcUpdateRequired(deviceExtension->Device))
3531     {
3532         // Issue command to update the drive capabilities.
3533         // The failure of MMC update is not considered critical,
3534         // so that we'll continue to process I/O even MMC update fails.
3535         DeviceUpdateMmcCapabilities(deviceExtension->Device);
3536     }
3537 
3538     RequestProcessSerializedIoctl(deviceExtension, deviceExtension->IoctlWorkItemContext.OriginalRequest);
3539 }
3540 
3541 
_IRQL_requires_max_(PASSIVE_LEVEL)3542 _IRQL_requires_max_(PASSIVE_LEVEL)
3543 NTSTATUS
3544 RequestProcessSerializedIoctl(
3545     _In_ PCDROM_DEVICE_EXTENSION  DeviceExtension,
3546     _In_ WDFREQUEST               Request
3547     )
3548 /*++
3549 Routine Description:
3550 
3551     a dispatch routine for all functions to process IOCTLs.
3552 
3553 Arguments:
3554 
3555     DeviceExtension - device context
3556 
3557     Request - handle to the incoming WDF Request object
3558 
3559 Return Value:
3560 
3561     NTSTATUS
3562 
3563 --*/
3564 {
3565     NTSTATUS                status = STATUS_SUCCESS;
3566     size_t                  information = 0;
3567     WDF_REQUEST_PARAMETERS  requestParameters;
3568     BOOLEAN                 completeRequest = TRUE;
3569 
3570     PAGED_CODE ();
3571 
3572     // Get the Request parameters
3573     WDF_REQUEST_PARAMETERS_INIT(&requestParameters);
3574     WdfRequestGetParameters(Request, &requestParameters);
3575 
3576     NormalizeIoctl(&requestParameters);
3577 
3578     // process IOCTLs
3579     switch (requestParameters.Parameters.DeviceIoControl.IoControlCode)
3580     {
3581     case IOCTL_CDROM_READ_TOC:
3582     case IOCTL_CDROM_GET_LAST_SESSION:
3583         status = RequestHandleReadTOC(DeviceExtension, Request, requestParameters, &information);
3584         break;
3585 
3586     case IOCTL_CDROM_READ_TOC_EX:
3587         status = RequestHandleReadTocEx(DeviceExtension, Request, requestParameters, &information);
3588         break;
3589 
3590     case IOCTL_CDROM_GET_CONFIGURATION:
3591         status = RequestHandleGetConfiguration(DeviceExtension, Request, requestParameters, &information);
3592         break;
3593 
3594     case IOCTL_CDROM_RAW_READ:
3595         status = DeviceHandleRawRead(DeviceExtension, Request, requestParameters, &information);
3596         break;
3597 
3598     case IOCTL_DISK_GET_LENGTH_INFO:
3599     case IOCTL_DISK_GET_DRIVE_GEOMETRY:
3600     case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX:
3601     case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
3602     case IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX:
3603     case IOCTL_STORAGE_READ_CAPACITY:
3604         status = RequestHandleGetDriveGeometry(DeviceExtension, Request, requestParameters, &information);
3605         break;
3606 
3607     case IOCTL_DISK_VERIFY:
3608         status = RequestHandleDiskVerify(DeviceExtension, Request, requestParameters, &information);
3609         break;
3610 
3611     case IOCTL_STORAGE_CHECK_VERIFY:
3612         // IOCTL_STORAGE_CHECK_VERIFY2 was processed including send a Test Unit Read
3613         // with srb flag SRB_CLASS_FLAGS_LOW_PRIORITY to port driver asynchronizelly.
3614         // The original request was completed after TUR finishes.
3615         // As CDROM.SYS serializes IOs need accessing device, it's not a big difference from above behavior to
3616         // just process it in serialized manner. So I put it here and treat it as same as IOCTL_STORAGE_CHECK_VERIFY.
3617     case IOCTL_STORAGE_CHECK_VERIFY2:
3618         status = RequestHandleCheckVerify(DeviceExtension, Request, requestParameters, &information);
3619         break;
3620 
3621     case IOCTL_DISK_GET_DRIVE_LAYOUT:
3622     case IOCTL_DISK_GET_DRIVE_LAYOUT_EX:
3623     case IOCTL_DISK_GET_PARTITION_INFO:
3624     case IOCTL_DISK_GET_PARTITION_INFO_EX:
3625         status = RequestHandleFakePartitionInfo(DeviceExtension, Request, requestParameters, &information);
3626         break;
3627 
3628     case IOCTL_DISK_IS_WRITABLE:
3629         //
3630         // Even though this media is writable, the requester of this IOCTL really
3631         // wants to know if thw media behaves like any other disk or not. This is
3632         // so if FeatureDefectManagement and FeatureRandomWritable are current on
3633         // the drive-represented by the FeatureDefectManagement validation schema
3634         //
3635         if (DeviceExtension->DeviceAdditionalData.Mmc.WriteAllowed &&
3636             (DeviceExtension->DeviceAdditionalData.Mmc.ValidationSchema == FeatureDefectManagement))
3637         {
3638             status = STATUS_SUCCESS;
3639         }
3640         else
3641         {
3642             status = STATUS_MEDIA_WRITE_PROTECTED;
3643         }
3644         information = 0;
3645         break;
3646 
3647     case IOCTL_CDROM_PLAY_AUDIO_MSF:
3648         status = DeviceHandlePlayAudioMsf(DeviceExtension, Request, requestParameters, &information);
3649         break;
3650 
3651     case IOCTL_CDROM_READ_Q_CHANNEL:
3652         status = DeviceHandleReadQChannel(DeviceExtension, Request, requestParameters, &information);
3653         break;
3654 
3655     case IOCTL_CDROM_PAUSE_AUDIO:
3656         status = DeviceHandlePauseAudio(DeviceExtension, Request, &information);
3657         break;
3658 
3659     case IOCTL_CDROM_RESUME_AUDIO:
3660         status = DeviceHandleResumeAudio(DeviceExtension, Request, &information);
3661         break;
3662 
3663     case IOCTL_CDROM_SEEK_AUDIO_MSF:
3664         status = DeviceHandleSeekAudioMsf(DeviceExtension, Request, requestParameters, &information);
3665         break;
3666 
3667     case IOCTL_CDROM_STOP_AUDIO:
3668         status = DeviceHandleStopAudio(DeviceExtension, Request, &information);
3669         break;
3670 
3671     case IOCTL_CDROM_GET_VOLUME:
3672     case IOCTL_CDROM_SET_VOLUME:
3673         status = DeviceHandleGetSetVolume(DeviceExtension, Request, requestParameters, &information);
3674         break;
3675 
3676     case IOCTL_DVD_GET_REGION:
3677         status = RequestHandleGetDvdRegion(DeviceExtension, Request, &information);
3678         break;
3679 
3680     case IOCTL_DVD_READ_STRUCTURE:
3681         status = DeviceHandleReadDvdStructure(DeviceExtension, Request, requestParameters, &information);
3682         break;
3683 
3684     case IOCTL_DVD_END_SESSION:
3685         status = DeviceHandleDvdEndSession(DeviceExtension, Request, requestParameters, &information);
3686         break;
3687 
3688     case IOCTL_DVD_START_SESSION:
3689     case IOCTL_DVD_READ_KEY:
3690         status = DeviceHandleDvdStartSessionReadKey(DeviceExtension, Request, requestParameters, &information);
3691         break;
3692 
3693     case IOCTL_DVD_SEND_KEY:
3694     case IOCTL_DVD_SEND_KEY2:
3695         status = DeviceHandleDvdSendKey(DeviceExtension, Request, requestParameters, &information);
3696         break;
3697 
3698     case IOCTL_STORAGE_SET_READ_AHEAD:
3699         status = DeviceHandleSetReadAhead(DeviceExtension, Request, requestParameters, &information);
3700         break;
3701 
3702     case IOCTL_CDROM_SET_SPEED:
3703         status = DeviceHandleSetSpeed(DeviceExtension, Request, requestParameters, &information);
3704         break;
3705 
3706     case IOCTL_AACS_READ_MEDIA_KEY_BLOCK_SIZE:
3707     case IOCTL_AACS_READ_MEDIA_KEY_BLOCK:
3708         status = DeviceHandleAacsReadMediaKeyBlock(DeviceExtension, Request, requestParameters, &information);
3709         break;
3710 
3711     case IOCTL_AACS_START_SESSION:
3712         status = DeviceHandleAacsStartSession(DeviceExtension, Request, requestParameters, &information);
3713         break;
3714 
3715     case IOCTL_AACS_END_SESSION:
3716         status = DeviceHandleAacsEndSession(DeviceExtension, Request, requestParameters, &information);
3717         break;
3718 
3719     case IOCTL_AACS_SEND_CERTIFICATE:
3720         status = DeviceHandleAacsSendCertificate(DeviceExtension, Request, requestParameters, &information);
3721         break;
3722 
3723     case IOCTL_AACS_GET_CERTIFICATE:
3724         status = DeviceHandleAacsGetCertificate(DeviceExtension, Request, requestParameters, &information);
3725         break;
3726 
3727     case IOCTL_AACS_GET_CHALLENGE_KEY:
3728         status = DeviceHandleAacsGetChallengeKey(DeviceExtension, Request, requestParameters, &information);
3729         break;
3730 
3731     case IOCTL_AACS_SEND_CHALLENGE_KEY:
3732         status = DeviceHandleSendChallengeKey(DeviceExtension, Request, requestParameters, &information);
3733         break;
3734 
3735     case IOCTL_AACS_READ_VOLUME_ID:
3736         status = DeviceHandleReadVolumeId(DeviceExtension, Request, requestParameters, &information);
3737         break;
3738 
3739     case IOCTL_AACS_READ_SERIAL_NUMBER:
3740         status = DeviceHandleAacsReadSerialNumber(DeviceExtension, Request, requestParameters, &information);
3741         break;
3742 
3743     case IOCTL_AACS_READ_MEDIA_ID:
3744         status = DeviceHandleAacsReadMediaId(DeviceExtension, Request, requestParameters, &information);
3745         break;
3746 
3747     case IOCTL_AACS_READ_BINDING_NONCE:
3748         status = DeviceHandleAacsReadBindingNonce(DeviceExtension, Request, requestParameters, &information);
3749         break;
3750 
3751     case IOCTL_AACS_GENERATE_BINDING_NONCE:
3752         status = DeviceHandleAacsGenerateBindingNonce(DeviceExtension, Request, requestParameters, &information);
3753         break;
3754 
3755     case IOCTL_CDROM_ENABLE_STREAMING:
3756         status = RequestHandleEnableStreaming(DeviceExtension, Request, &information);
3757         break;
3758 
3759     case IOCTL_CDROM_SEND_OPC_INFORMATION:
3760         status = RequestHandleSendOpcInformation(DeviceExtension, Request, &information);
3761         break;
3762 
3763     case IOCTL_CDROM_GET_PERFORMANCE:
3764         status = RequestHandleGetPerformance(DeviceExtension, Request, requestParameters, &information);
3765         break;
3766 
3767     // This IOCTL is a fake one, used for MCN process sync-ed with serial queue.
3768     case IOCTL_MCN_SYNC_FAKE_IOCTL:
3769         status = RequestHandleMcnSyncFakeIoctl(DeviceExtension, &information);
3770         break;
3771 
3772     case IOCTL_STORAGE_MEDIA_REMOVAL:
3773     case IOCTL_STORAGE_EJECTION_CONTROL:
3774     {
3775         status = RequestHandleEjectionControl(DeviceExtension, Request, requestParameters, &information);
3776 
3777         break;
3778     }
3779 
3780     case IOCTL_STORAGE_EJECT_MEDIA:
3781     case IOCTL_STORAGE_LOAD_MEDIA:
3782     case IOCTL_STORAGE_LOAD_MEDIA2:
3783     {
3784         status = RequestHandleLoadEjectMedia(DeviceExtension, Request, requestParameters, &information);
3785 
3786         break;
3787     }
3788 
3789     case IOCTL_STORAGE_MCN_CONTROL:
3790     {
3791         status = RequestHandleMcnControl(DeviceExtension, Request, &information);
3792 
3793         break;
3794     }
3795 
3796     case IOCTL_STORAGE_RESERVE:
3797     case IOCTL_STORAGE_RELEASE:
3798     {
3799         status = RequestHandleReserveRelease(DeviceExtension, Request, requestParameters, &information);
3800 
3801         break;
3802     }
3803 
3804     case IOCTL_STORAGE_PERSISTENT_RESERVE_IN:
3805     case IOCTL_STORAGE_PERSISTENT_RESERVE_OUT:
3806     {
3807         status = RequestHandlePersistentReserve(DeviceExtension, Request, requestParameters, &information);
3808 
3809         break;
3810     }
3811 
3812 #if (NTDDI_VERSION >= NTDDI_WIN8)
3813     case IOCTL_DISK_ARE_VOLUMES_READY:
3814     {
3815         status = RequestHandleAreVolumesReady(DeviceExtension, Request, requestParameters, &information);
3816 
3817         completeRequest = FALSE;
3818 
3819         break;
3820     }
3821 
3822     case IOCTL_VOLUME_ONLINE:
3823     case IOCTL_VOLUME_POST_ONLINE:
3824     {
3825         status = RequestHandleVolumeOnline(DeviceExtension, Request, requestParameters, &information);
3826 
3827         break;
3828     }
3829 #endif
3830 
3831     default:
3832     {
3833         status = STATUS_ACCESS_DENIED;
3834         break;
3835     }
3836     } // end of switch(ioctl)
3837 
3838     if (completeRequest)
3839     {
3840         RequestCompletion(DeviceExtension, Request, status, information);
3841     }
3842 
3843     return status;
3844 }
3845 
3846 VOID
3847 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
SequentialQueueEvtCanceledOnQueue(_In_ WDFQUEUE Queue,_In_ WDFREQUEST Request)3848 SequentialQueueEvtCanceledOnQueue(
3849     _In_ WDFQUEUE   Queue,
3850     _In_ WDFREQUEST Request
3851     )
3852 /*++
3853 Routine Description:
3854 
3855     Perform cancellation when request is still in queue.
3856 
3857     If request is sych-ed in another thread, signal the event to let that thread be able to complete the request.
3858     Otherwise, complete the request.
3859 
3860 Arguments:
3861 
3862     Queue - serial queue
3863     Request - handle to the incoming WDF Request object
3864 
3865 Return Value:
3866 
3867     None
3868 
3869 --*/
3870 {
3871     PCDROM_REQUEST_CONTEXT  requestContext = RequestGetContext(Request);
3872 
3873     if (requestContext->SyncRequired)
3874     {
3875         KeSetEvent(requestContext->SyncEvent, IO_CD_ROM_INCREMENT, FALSE);
3876     }
3877     else
3878     {
3879         PCDROM_DEVICE_EXTENSION deviceExtension = NULL;
3880         WDFDEVICE               device = WdfIoQueueGetDevice(Queue);
3881 
3882         deviceExtension = DeviceGetExtension(device);
3883 
3884         RequestCompletion(deviceExtension, Request, STATUS_CANCELLED, 0);
3885 
3886     }
3887 
3888     return;
3889 }
3890 
3891 
3892 NTSTATUS
RequestSynchronizeProcessWithSerialQueue(_In_ WDFDEVICE Device,_In_ WDFREQUEST Request)3893 RequestSynchronizeProcessWithSerialQueue(
3894     _In_ WDFDEVICE Device,
3895     _In_ WDFREQUEST Request
3896     )
3897 /*++
3898 Routine Description:
3899 
3900     This is the mechanism to sync a request process in original thread with serialize queue.
3901     initialize a EVENT and put the request inot serialize queue;
3902     waiting for serialize queue processes to this request and signal the EVENT;
3903     call the request handler to process this request.
3904 
3905 Arguments:
3906 
3907     DeviceExtension - device context
3908 
3909     Request - handle to the incoming WDF Request object
3910 
3911 Return Value:
3912 
3913     NTSTATUS
3914 
3915 --*/
3916 {
3917     NTSTATUS                status = STATUS_SUCCESS;
3918     PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device);
3919     PCDROM_REQUEST_CONTEXT  requestContext = RequestGetContext(Request);
3920     PKEVENT                 bufferToFree = requestContext->SyncEvent;
3921 
3922     if (KeGetCurrentIrql() >= DISPATCH_LEVEL) {
3923         // cannot block at or above DISPATCH_LEVEL
3924         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL,
3925             "RequestSynchronousProcessWithSerialQueue called at DISPATCH_LEVEL or above"));
3926         NT_ASSERT(FALSE);
3927         RequestCompletion(deviceExtension, Request, STATUS_INVALID_LEVEL, 0);
3928         return STATUS_INVALID_LEVEL;
3929     }
3930 
3931     // init the synchronization event
3932     KeInitializeEvent(requestContext->SyncEvent, NotificationEvent, FALSE);
3933 
3934     // do we still need to do something like this?
3935     // SET_FLAG(nextStack->Flags, SL_OVERRIDE_VERIFY_VOLUME);
3936 
3937     // NOTE: this mechanism relies on that KMDF will not complete request by itself.
3938     // Doing that will cause the syncEvent not fired thus this thread will stuck.
3939     // This should not really happen: our EvtCanceledOnQueue callbacks should be
3940     // called even if queues are purged for some reason. The only case when these
3941     // callbacks are not called is when a request is owned by the driver (i.e. has
3942     // already been passed to one of the registered handlers). In this case, it is
3943     // our responsibility to cancel such requests properly.
3944     status = WdfDeviceEnqueueRequest(Device, Request);
3945 
3946     if (!NT_SUCCESS(status))
3947     {
3948         // Failed to forward request! Pretend the sync event already occured, otherwise we'll hit
3949         // an assert in RequestEvtCleanup.
3950         KeSetEvent(requestContext->SyncEvent, IO_CD_ROM_INCREMENT, FALSE);
3951         RequestCompletion(deviceExtension, Request, status, WdfRequestGetInformation(Request));
3952     }
3953     else
3954     {
3955         NTSTATUS                waitStatus = STATUS_UNSUCCESSFUL;
3956         PCDROM_DATA             cdData = &(deviceExtension->DeviceAdditionalData);
3957         BOOLEAN                 fCallSyncCallback = FALSE;
3958         PIRP                    irp = WdfRequestWdmGetIrp(Request);
3959 
3960         // ok, now wait on the event
3961         while (waitStatus != STATUS_SUCCESS)
3962         {
3963             waitStatus = KeWaitForSingleObject(requestContext->SyncEvent, Executive, KernelMode, TRUE, NULL);
3964             if (waitStatus == STATUS_SUCCESS) // must check equality -- STATUS_ALERTED is success code
3965             {
3966                 // do nothing
3967             }
3968             else if (waitStatus != STATUS_ALERTED)
3969             {
3970                 // do nothing
3971                 TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_IOCTL,
3972                             "Request %p on device object %p had a non-alert, non-success result from wait (%!HRESULT!)\n",
3973                             Request, Device, waitStatus));
3974                 NT_ASSERT(FALSE);
3975             }
3976             else if (PsIsThreadTerminating(PsGetCurrentThread()))
3977             {
3978                 // the thread was alerted and is terminating, so cancel the irp
3979                 // this will cause EvtIoCanceledOnQueue to be called, which will signal the event,
3980                 // so we will get out of the while loop and eventually complete the request.
3981                 if (IoCancelIrp(irp))
3982                 {
3983                     // cancellation routine was called
3984                     TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
3985                                 "Sychronize Ioctl: request %p cancelled from device %p\n",
3986                                 Request, Device));
3987                 }
3988                 else
3989                 {
3990                     TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
3991                                 "Sychronize Ioctl: request %p could not be cancelled from device %p\n",
3992                                 Request, Device));
3993                 }
3994             }
3995             else
3996             {
3997                 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
3998                             "SPURIOUS ALERT waiting for Request %p on device %p (%!STATUS!)\n",
3999                             Request, Device, status));
4000             }
4001         } // end of wait loop on the event
4002 
4003         // because we've waited an unknown amount of time, should check
4004         // the cancelled flag to immediately fail the irp as appropriate
4005         if (WdfRequestIsCanceled(Request))
4006         {
4007             // the request was cancelled, thus we should always stop
4008             // processing here if possible.
4009             status = STATUS_CANCELLED;
4010             RequestCompletion(deviceExtension, Request, status, 0);
4011         }
4012         else if (EXCLUSIVE_MODE(cdData) && !EXCLUSIVE_OWNER(cdData, WdfRequestGetFileObject(Request)))
4013         {
4014             WDF_REQUEST_PARAMETERS  requestParameters;
4015             BOOLEAN                 isBlocked = FALSE;
4016 
4017             // get the request parameters
4018             WDF_REQUEST_PARAMETERS_INIT(&requestParameters);
4019             WdfRequestGetParameters(Request, &requestParameters);
4020 
4021             status = RequestIsIoctlBlockedByExclusiveAccess(Request, &isBlocked);
4022             if (isBlocked)
4023             {
4024                 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL,
4025                             "Access Denied! Device in exclusive mode.Failing Ioctl %lx\n",
4026                             requestParameters.Parameters.DeviceIoControl.IoControlCode));
4027                 RequestCompletion(deviceExtension, Request, STATUS_ACCESS_DENIED, 0);
4028             }
4029             else
4030             {
4031                 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
4032                             "Ioctl %lx not blocked by cdrom being in exclusive mode\n",
4033                             requestParameters.Parameters.DeviceIoControl.IoControlCode));
4034                 fCallSyncCallback = TRUE;
4035             }
4036         }
4037         else
4038         {
4039             fCallSyncCallback = TRUE;
4040         }
4041 
4042         if (fCallSyncCallback)
4043         {
4044             // Synchronization completed successfully.  Call the requested routine
4045             status = requestContext->SyncCallback(Device, Request);
4046         }
4047     }
4048 
4049     // The next SequentialQueue evt routine will not be triggered until the current request is completed.
4050 
4051     // clean up the request context setting.
4052     FREE_POOL(bufferToFree);
4053 
4054     return status;
4055 }
4056 
4057 NTSTATUS
RequestIsIoctlBlockedByExclusiveAccess(_In_ WDFREQUEST Request,_Out_ PBOOLEAN IsBlocked)4058 RequestIsIoctlBlockedByExclusiveAccess(
4059     _In_  WDFREQUEST  Request,
4060     _Out_ PBOOLEAN    IsBlocked
4061     )
4062 /*++
4063 Routine Description:
4064 
4065     Check if the IOCTL request should be blocked or not according to
4066     the exclusive lock stat.
4067 
4068 Arguments:
4069 
4070     Request - handle to the incoming WDF Request object
4071 
4072 Return Value:
4073 
4074     NTSTATUS
4075 
4076     IsBlocked - TRUE (be blocked); FALSE (not blocked)
4077 
4078 --*/
4079 {
4080     NTSTATUS                status = STATUS_SUCCESS;
4081     ULONG                   ioctlCode = 0;
4082     ULONG                   baseCode = 0;
4083     WDF_REQUEST_PARAMETERS  requestParameters;
4084 
4085     // Get the Request parameters
4086     WDF_REQUEST_PARAMETERS_INIT(&requestParameters);
4087     WdfRequestGetParameters(Request, &requestParameters);
4088 
4089     // check and initialize parameter
4090     if (IsBlocked == NULL)
4091     {
4092         //This is an internal function and this parameter must be supplied.
4093         NT_ASSERT(FALSE);
4094 
4095         return STATUS_INVALID_PARAMETER;
4096     }
4097     else
4098     {
4099         *IsBlocked = FALSE;
4100     }
4101 
4102     // check if this is an IOCTL
4103     if ((requestParameters.Type == WdfRequestTypeDeviceControl) ||
4104         (requestParameters.Type == WdfRequestTypeDeviceControlInternal))
4105     {
4106         //
4107         // Allow minimum set of commands that are required for the disk manager
4108         // to show the CD device, while in exclusive mode.
4109         // Note: These commands should not generate any requests to the device,
4110         //       and thus must be handled directly in StartIO during exclusive
4111         //       access (except for the exclusive owner, of course).
4112         //
4113         ioctlCode = requestParameters.Parameters.DeviceIoControl.IoControlCode;
4114         baseCode = DEVICE_TYPE_FROM_CTL_CODE(ioctlCode);
4115 
4116         if (ioctlCode == IOCTL_SCSI_GET_ADDRESS           ||
4117             ioctlCode == IOCTL_STORAGE_GET_HOTPLUG_INFO   ||
4118             ioctlCode == IOCTL_STORAGE_GET_DEVICE_NUMBER  ||
4119             ioctlCode == IOCTL_STORAGE_GET_MEDIA_TYPES_EX ||
4120             ioctlCode == IOCTL_CDROM_EXCLUSIVE_ACCESS     ||
4121             ioctlCode == IOCTL_CDROM_GET_INQUIRY_DATA
4122             )
4123         {
4124             *IsBlocked = FALSE;
4125         }
4126 
4127         //
4128         // Handle IOCTL_STORAGE_QUERY_PROPERTY special because:
4129         //  (1) PropertyExistsQuery should not generate device i/o
4130         //  (2) Queries for StorageDeviceProperty and StorageAdapterDescriptor
4131         //      will return cache'd data
4132     else if (ioctlCode == IOCTL_STORAGE_QUERY_PROPERTY)
4133         {
4134             PSTORAGE_PROPERTY_QUERY query = NULL;
4135             status = WdfRequestRetrieveInputBuffer(Request,
4136                                                    requestParameters.Parameters.DeviceIoControl.InputBufferLength,
4137                                                    (PVOID*)&query,
4138                                                    NULL);
4139 
4140             if (NT_SUCCESS(status))
4141             {
4142                 if (query != NULL)
4143                 {
4144                     if (query->QueryType == PropertyExistsQuery)
4145                     {
4146                         *IsBlocked = FALSE;
4147                     }
4148                     else if ((query->QueryType == PropertyStandardQuery) &&
4149                              ((query->PropertyId == StorageDeviceProperty) ||
4150                               (query->PropertyId == StorageAdapterProperty)))
4151                     {
4152                         *IsBlocked = FALSE;
4153                     }
4154                 }
4155             }
4156         }
4157 
4158         // Return TRUE for unknown IOCTLs with STORAGE bases
4159     else if (baseCode == IOCTL_SCSI_BASE    ||
4160             baseCode == IOCTL_DISK_BASE    ||
4161             baseCode == IOCTL_CDROM_BASE   ||
4162             baseCode == IOCTL_STORAGE_BASE ||
4163             baseCode == IOCTL_DVD_BASE     )
4164         {
4165             *IsBlocked = TRUE;
4166         }
4167     }
4168     else
4169     {
4170         // this should only be called with an IOCTL
4171         NT_ASSERT(FALSE);
4172 
4173         status = STATUS_INVALID_PARAMETER;
4174     }
4175 
4176     return status;
4177 }
4178 
4179 BOOLEAN
DeviceIsMmcUpdateRequired(_In_ WDFDEVICE Device)4180 DeviceIsMmcUpdateRequired(
4181     _In_ WDFDEVICE    Device
4182     )
4183 /*++
4184 Routine Description:
4185 
4186     Check if the device needs to update its MMC information.
4187 
4188 Arguments:
4189 
4190     Device - device to be checked.
4191 
4192 Return Value:
4193 
4194     TRUE (require update); FALSE (not require update)
4195 
4196 --*/
4197 {
4198     PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device);
4199     PCDROM_DATA             cdData = &(deviceExtension->DeviceAdditionalData);
4200 
4201     if ((cdData->Mmc.IsMmc) &&
4202         (cdData->Mmc.UpdateState == CdromMmcUpdateRequired))
4203     {
4204         return TRUE;
4205     }
4206     else
4207     {
4208         // no update required: just proceed
4209         return FALSE;
4210     }
4211 }
4212 
4213 VOID
4214 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
RequestEvtCleanup(_In_ WDFOBJECT Request)4215 RequestEvtCleanup(
4216     _In_ WDFOBJECT Request
4217     )
4218 /*++
4219 Routine Description:
4220 
4221     Request cleanup callback.
4222 
4223 Arguments:
4224 
4225     Request - request to clean up.
4226 
4227 Return Value:
4228 
4229     None
4230 
4231 --*/
4232 {
4233     WDFREQUEST              request = (WDFREQUEST)Request;
4234     PCDROM_REQUEST_CONTEXT  requestContext = RequestGetContext(request);
4235 
4236     if (requestContext->SyncRequired)
4237     {
4238         // the event should have been signaled, just check that
4239         NT_ASSERT(KeReadStateEvent(requestContext->SyncEvent) != 0);
4240     }
4241 }
4242 
4243