[CDROM_NEW] Import Microsoft CDROM class driver from GitHub
[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);