[IMM32] Improve ImmGetImeInfoEx (#3833)
[reactos.git] / drivers / storage / class / cdrom_new / cdrom.c
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 */
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
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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
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
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
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 */
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
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
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
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
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
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
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 */
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 */
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 */
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 */
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
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 */
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
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
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
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 */
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