xref: /reactos/drivers/storage/class/cdrom/init.c (revision 3088717b)
1*3088717bSVictor Perevertkin /*--
2*3088717bSVictor Perevertkin 
3*3088717bSVictor Perevertkin Copyright (C) Microsoft Corporation. All rights reserved.
4*3088717bSVictor Perevertkin 
5*3088717bSVictor Perevertkin Module Name:
6*3088717bSVictor Perevertkin 
7*3088717bSVictor Perevertkin     init.c
8*3088717bSVictor Perevertkin 
9*3088717bSVictor Perevertkin Abstract:
10*3088717bSVictor Perevertkin 
11*3088717bSVictor Perevertkin     Initialization routines for CDROM
12*3088717bSVictor Perevertkin 
13*3088717bSVictor Perevertkin Environment:
14*3088717bSVictor Perevertkin 
15*3088717bSVictor Perevertkin     kernel mode only
16*3088717bSVictor Perevertkin 
17*3088717bSVictor Perevertkin Notes:
18*3088717bSVictor Perevertkin 
19*3088717bSVictor Perevertkin 
20*3088717bSVictor Perevertkin Revision History:
21*3088717bSVictor Perevertkin 
22*3088717bSVictor Perevertkin --*/
23*3088717bSVictor Perevertkin 
24*3088717bSVictor Perevertkin 
25*3088717bSVictor Perevertkin #include "ntddk.h"
26*3088717bSVictor Perevertkin #include "ntddstor.h"
27*3088717bSVictor Perevertkin #include "ntstrsafe.h"
28*3088717bSVictor Perevertkin #include "devpkey.h"
29*3088717bSVictor Perevertkin 
30*3088717bSVictor Perevertkin #include "cdrom.h"
31*3088717bSVictor Perevertkin #include "scratch.h"
32*3088717bSVictor Perevertkin #include "mmc.h"
33*3088717bSVictor Perevertkin 
34*3088717bSVictor Perevertkin #ifdef DEBUG_USE_WPP
35*3088717bSVictor Perevertkin #include "init.tmh"
36*3088717bSVictor Perevertkin #endif
37*3088717bSVictor Perevertkin 
38*3088717bSVictor Perevertkin _IRQL_requires_max_(APC_LEVEL)
39*3088717bSVictor Perevertkin NTSTATUS
40*3088717bSVictor Perevertkin DeviceInitAllocateBuffers(
41*3088717bSVictor Perevertkin     _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
42*3088717bSVictor Perevertkin     );
43*3088717bSVictor Perevertkin 
44*3088717bSVictor Perevertkin _IRQL_requires_max_(PASSIVE_LEVEL)
45*3088717bSVictor Perevertkin NTSTATUS
46*3088717bSVictor Perevertkin DeviceRetrieveScsiAddress(
47*3088717bSVictor Perevertkin     _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
48*3088717bSVictor Perevertkin     _In_ PSCSI_ADDRESS           ScsiAddress
49*3088717bSVictor Perevertkin     );
50*3088717bSVictor Perevertkin 
51*3088717bSVictor Perevertkin _IRQL_requires_max_(PASSIVE_LEVEL)
52*3088717bSVictor Perevertkin NTSTATUS
53*3088717bSVictor Perevertkin DeviceRetrieveDescriptorsAndTransferLength(
54*3088717bSVictor Perevertkin     _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
55*3088717bSVictor Perevertkin     );
56*3088717bSVictor Perevertkin 
57*3088717bSVictor Perevertkin _IRQL_requires_max_(APC_LEVEL)
58*3088717bSVictor Perevertkin VOID
59*3088717bSVictor Perevertkin DeviceScanSpecialDevices(
60*3088717bSVictor Perevertkin     _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
61*3088717bSVictor Perevertkin     );
62*3088717bSVictor Perevertkin 
63*3088717bSVictor Perevertkin _IRQL_requires_max_(PASSIVE_LEVEL)
64*3088717bSVictor Perevertkin NTSTATUS
65*3088717bSVictor Perevertkin DeviceInitMmcContext(
66*3088717bSVictor Perevertkin     _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
67*3088717bSVictor Perevertkin     );
68*3088717bSVictor Perevertkin 
69*3088717bSVictor Perevertkin _IRQL_requires_max_(PASSIVE_LEVEL)
70*3088717bSVictor Perevertkin NTSTATUS
71*3088717bSVictor Perevertkin DeviceGetMmcSupportInfo(
72*3088717bSVictor Perevertkin     _In_  PCDROM_DEVICE_EXTENSION   DeviceExtension,
73*3088717bSVictor Perevertkin     _Out_ PBOOLEAN                  IsMmcDevice
74*3088717bSVictor Perevertkin     );
75*3088717bSVictor Perevertkin 
76*3088717bSVictor Perevertkin #if (NTDDI_VERSION >= NTDDI_WIN8)
77*3088717bSVictor Perevertkin _IRQL_requires_max_(PASSIVE_LEVEL)
78*3088717bSVictor Perevertkin NTSTATUS
79*3088717bSVictor Perevertkin DeviceIsPortable(
80*3088717bSVictor Perevertkin     _In_  PCDROM_DEVICE_EXTENSION   DeviceExtension,
81*3088717bSVictor Perevertkin     _Out_ PBOOLEAN                  IsPortable
82*3088717bSVictor Perevertkin     );
83*3088717bSVictor Perevertkin #endif
84*3088717bSVictor Perevertkin 
85*3088717bSVictor Perevertkin 
86*3088717bSVictor Perevertkin #ifdef ALLOC_PRAGMA
87*3088717bSVictor Perevertkin 
88*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DeviceClaimRelease)
89*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DeviceEvtSelfManagedIoInit)
90*3088717bSVictor Perevertkin 
91*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DeviceInitReleaseQueueContext)
92*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DeviceInitAllocateBuffers)
93*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DeviceInitPowerContext)
94*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DeviceCreateWellKnownName)
95*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DeviceRetrieveScsiAddress)
96*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DeviceRetrieveDescriptorsAndTransferLength)
97*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DeviceInitializeHotplugInfo)
98*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DeviceScanSpecialDevices)
99*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DeviceGetTimeOutValueFromRegistry)
100*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DeviceGetMmcSupportInfo)
101*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DeviceRetrieveDescriptor)
102*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DeviceRetrieveHackFlagsFromRegistry)
103*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DeviceScanForSpecial)
104*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DeviceHackFlagsScan)
105*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DeviceInitMmcContext)
106*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, ScanForSpecialHandler)
107*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DeviceSetRawReadInfo)
108*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DeviceInitializeDvd)
109*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DeviceCacheDeviceInquiryData)
110*3088717bSVictor Perevertkin 
111*3088717bSVictor Perevertkin #if (NTDDI_VERSION >= NTDDI_WIN8)
112*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, DeviceIsPortable)
113*3088717bSVictor Perevertkin #endif
114*3088717bSVictor Perevertkin 
115*3088717bSVictor Perevertkin #endif
116*3088717bSVictor Perevertkin 
117*3088717bSVictor Perevertkin #pragma warning(push)
118*3088717bSVictor Perevertkin #pragma warning(disable:4152) // nonstandard extension, function/data pointer conversion in expression
119*3088717bSVictor Perevertkin #pragma warning(disable:26000) // read overflow reported because of pointer type conversion
120*3088717bSVictor Perevertkin 
_IRQL_requires_max_(PASSIVE_LEVEL)121*3088717bSVictor Perevertkin _IRQL_requires_max_(PASSIVE_LEVEL)
122*3088717bSVictor Perevertkin NTSTATUS
123*3088717bSVictor Perevertkin DeviceClaimRelease(
124*3088717bSVictor Perevertkin     _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
125*3088717bSVictor Perevertkin     _In_ BOOLEAN                 Release
126*3088717bSVictor Perevertkin     )
127*3088717bSVictor Perevertkin /*++
128*3088717bSVictor Perevertkin 
129*3088717bSVictor Perevertkin Routine Description:
130*3088717bSVictor Perevertkin 
131*3088717bSVictor Perevertkin     This function claims a device in the port driver.  The port driver object
132*3088717bSVictor Perevertkin     is updated with the correct driver object if the device is successfully
133*3088717bSVictor Perevertkin     claimed.
134*3088717bSVictor Perevertkin 
135*3088717bSVictor Perevertkin Arguments:
136*3088717bSVictor Perevertkin 
137*3088717bSVictor Perevertkin     Device - The WDFDEVICE that needs to be claimed or released.
138*3088717bSVictor Perevertkin 
139*3088717bSVictor Perevertkin     Release - Indicates the logical unit should be released rather than claimed.
140*3088717bSVictor Perevertkin 
141*3088717bSVictor Perevertkin Return Value:
142*3088717bSVictor Perevertkin 
143*3088717bSVictor Perevertkin     Returns a status indicating success or failure of the operation.
144*3088717bSVictor Perevertkin 
145*3088717bSVictor Perevertkin --*/
146*3088717bSVictor Perevertkin {
147*3088717bSVictor Perevertkin     NTSTATUS                status;
148*3088717bSVictor Perevertkin     SCSI_REQUEST_BLOCK      srb = {0};
149*3088717bSVictor Perevertkin     WDF_MEMORY_DESCRIPTOR   descriptor;
150*3088717bSVictor Perevertkin     WDFREQUEST              request;
151*3088717bSVictor Perevertkin     WDF_OBJECT_ATTRIBUTES   attributes;
152*3088717bSVictor Perevertkin 
153*3088717bSVictor Perevertkin     PAGED_CODE();
154*3088717bSVictor Perevertkin 
155*3088717bSVictor Perevertkin     //Create a request
156*3088717bSVictor Perevertkin     WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes,
157*3088717bSVictor Perevertkin                                             CDROM_REQUEST_CONTEXT);
158*3088717bSVictor Perevertkin 
159*3088717bSVictor Perevertkin     status = WdfRequestCreate(&attributes,
160*3088717bSVictor Perevertkin                               DeviceExtension->IoTarget,
161*3088717bSVictor Perevertkin                               &request);
162*3088717bSVictor Perevertkin 
163*3088717bSVictor Perevertkin     if (NT_SUCCESS(status))
164*3088717bSVictor Perevertkin     {
165*3088717bSVictor Perevertkin         //fill up srb structure
166*3088717bSVictor Perevertkin         srb.OriginalRequest = WdfRequestWdmGetIrp(request);
167*3088717bSVictor Perevertkin         NT_ASSERT(srb.OriginalRequest != NULL);
168*3088717bSVictor Perevertkin 
169*3088717bSVictor Perevertkin         srb.Length = sizeof(SCSI_REQUEST_BLOCK);
170*3088717bSVictor Perevertkin 
171*3088717bSVictor Perevertkin         srb.Function = Release
172*3088717bSVictor Perevertkin                         ? SRB_FUNCTION_RELEASE_DEVICE
173*3088717bSVictor Perevertkin                         : SRB_FUNCTION_CLAIM_DEVICE;
174*3088717bSVictor Perevertkin 
175*3088717bSVictor Perevertkin 
176*3088717bSVictor Perevertkin         WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&descriptor,
177*3088717bSVictor Perevertkin                                           &srb,
178*3088717bSVictor Perevertkin                                           sizeof(srb));
179*3088717bSVictor Perevertkin 
180*3088717bSVictor Perevertkin         status = WdfIoTargetSendInternalIoctlOthersSynchronously(DeviceExtension->IoTarget,
181*3088717bSVictor Perevertkin                                                                  request,
182*3088717bSVictor Perevertkin                                                                  IOCTL_SCSI_EXECUTE_NONE,
183*3088717bSVictor Perevertkin                                                                  &descriptor,
184*3088717bSVictor Perevertkin                                                                  NULL,
185*3088717bSVictor Perevertkin                                                                  NULL,
186*3088717bSVictor Perevertkin                                                                  NULL,
187*3088717bSVictor Perevertkin                                                                  NULL);
188*3088717bSVictor Perevertkin 
189*3088717bSVictor Perevertkin         NT_ASSERT(!TEST_FLAG(srb.SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER));
190*3088717bSVictor Perevertkin 
191*3088717bSVictor Perevertkin         // The request should be deleted.
192*3088717bSVictor Perevertkin         WdfObjectDelete(request);
193*3088717bSVictor Perevertkin 
194*3088717bSVictor Perevertkin         if (!NT_SUCCESS(status))
195*3088717bSVictor Perevertkin         {
196*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP,
197*3088717bSVictor Perevertkin                         "DeviceClaimRelease: Failed to %s device, status: 0x%X\n",
198*3088717bSVictor Perevertkin                         Release ? "Release" : "Claim",
199*3088717bSVictor Perevertkin                         status));
200*3088717bSVictor Perevertkin         }
201*3088717bSVictor Perevertkin     }
202*3088717bSVictor Perevertkin     else
203*3088717bSVictor Perevertkin     {
204*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP,
205*3088717bSVictor Perevertkin                     "DeviceClaimRelease: Failed to create request, status: 0x%X\n",
206*3088717bSVictor Perevertkin                     status));
207*3088717bSVictor Perevertkin     }
208*3088717bSVictor Perevertkin 
209*3088717bSVictor Perevertkin     if (Release)
210*3088717bSVictor Perevertkin     {
211*3088717bSVictor Perevertkin         // We only release the device when we don't want to manage it.
212*3088717bSVictor Perevertkin         // The failure status does not matter.
213*3088717bSVictor Perevertkin         status = STATUS_SUCCESS;
214*3088717bSVictor Perevertkin     }
215*3088717bSVictor Perevertkin 
216*3088717bSVictor Perevertkin     return status;
217*3088717bSVictor Perevertkin } // end DeviceClaimRelease()
218*3088717bSVictor Perevertkin 
219*3088717bSVictor Perevertkin 
220*3088717bSVictor Perevertkin NTSTATUS
221*3088717bSVictor Perevertkin NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DeviceEvtSelfManagedIoInit(_In_ WDFDEVICE Device)222*3088717bSVictor Perevertkin DeviceEvtSelfManagedIoInit(
223*3088717bSVictor Perevertkin     _In_ WDFDEVICE      Device
224*3088717bSVictor Perevertkin     )
225*3088717bSVictor Perevertkin /*++
226*3088717bSVictor Perevertkin 
227*3088717bSVictor Perevertkin Routine Description:
228*3088717bSVictor Perevertkin 
229*3088717bSVictor Perevertkin     This routine is called only once after the device is added in system, so it's used to do
230*3088717bSVictor Perevertkin     hardware-dependent device initialization work and resource allocation.
231*3088717bSVictor Perevertkin     If this routine fails, DeviceEvtSelfManagedIoCleanup will be invoked by the framework.
232*3088717bSVictor Perevertkin 
233*3088717bSVictor Perevertkin Arguments:
234*3088717bSVictor Perevertkin 
235*3088717bSVictor Perevertkin     Device - Handle to device object
236*3088717bSVictor Perevertkin 
237*3088717bSVictor Perevertkin Return Value:
238*3088717bSVictor Perevertkin 
239*3088717bSVictor Perevertkin     NTSTATUS
240*3088717bSVictor Perevertkin 
241*3088717bSVictor Perevertkin --*/
242*3088717bSVictor Perevertkin {
243*3088717bSVictor Perevertkin     NTSTATUS                status = STATUS_SUCCESS;
244*3088717bSVictor Perevertkin     PCDROM_DEVICE_EXTENSION deviceExtension = NULL;
245*3088717bSVictor Perevertkin 
246*3088717bSVictor Perevertkin     PAGED_CODE();
247*3088717bSVictor Perevertkin 
248*3088717bSVictor Perevertkin     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP,
249*3088717bSVictor Perevertkin                 "DeviceEvtSelfManagedIoInit: WDFDEVICE %p is being started.\n",
250*3088717bSVictor Perevertkin                 Device));
251*3088717bSVictor Perevertkin 
252*3088717bSVictor Perevertkin     deviceExtension = DeviceGetExtension(Device);
253*3088717bSVictor Perevertkin 
254*3088717bSVictor Perevertkin     // 1. Set/retrieve basic information, some of the following operations may depend on it
255*3088717bSVictor Perevertkin     if (NT_SUCCESS(status))
256*3088717bSVictor Perevertkin     {
257*3088717bSVictor Perevertkin         // We do not care if this function fails, SCSI address is mainly for debugging/tracing purposes.
258*3088717bSVictor Perevertkin         (VOID) DeviceRetrieveScsiAddress(deviceExtension, &deviceExtension->ScsiAddress);
259*3088717bSVictor Perevertkin     }
260*3088717bSVictor Perevertkin 
261*3088717bSVictor Perevertkin     if (NT_SUCCESS(status))
262*3088717bSVictor Perevertkin     {
263*3088717bSVictor Perevertkin         status = DeviceRetrieveDescriptorsAndTransferLength(deviceExtension);
264*3088717bSVictor Perevertkin     }
265*3088717bSVictor Perevertkin 
266*3088717bSVictor Perevertkin     if (NT_SUCCESS(status))
267*3088717bSVictor Perevertkin     {
268*3088717bSVictor Perevertkin         // This function should be called after DeviceRetrieveDescriptorsAndTransferLength()
269*3088717bSVictor Perevertkin         // It depends on MaxTransferLenth fields.
270*3088717bSVictor Perevertkin         status = DeviceInitAllocateBuffers(deviceExtension);
271*3088717bSVictor Perevertkin     }
272*3088717bSVictor Perevertkin 
273*3088717bSVictor Perevertkin     // 2. The following functions depend on the allocated buffers.
274*3088717bSVictor Perevertkin 
275*3088717bSVictor Perevertkin     // perf re-enable after failing. Q: Is this one used by cdrom.sys?
276*3088717bSVictor Perevertkin     if (NT_SUCCESS(status))
277*3088717bSVictor Perevertkin     {
278*3088717bSVictor Perevertkin         // allow perf to be re-enabled after a given number of failed IOs
279*3088717bSVictor Perevertkin         // require this number to be at least CLASS_PERF_RESTORE_MINIMUM
280*3088717bSVictor Perevertkin         ULONG t = CLASS_PERF_RESTORE_MINIMUM;
281*3088717bSVictor Perevertkin 
282*3088717bSVictor Perevertkin         DeviceGetParameter(deviceExtension,
283*3088717bSVictor Perevertkin                            CLASSP_REG_SUBKEY_NAME,
284*3088717bSVictor Perevertkin                            CLASSP_REG_PERF_RESTORE_VALUE_NAME,
285*3088717bSVictor Perevertkin                            &t);
286*3088717bSVictor Perevertkin         if (t >= CLASS_PERF_RESTORE_MINIMUM)
287*3088717bSVictor Perevertkin         {
288*3088717bSVictor Perevertkin             deviceExtension->PrivateFdoData->Perf.ReEnableThreshhold = t;
289*3088717bSVictor Perevertkin         }
290*3088717bSVictor Perevertkin     }
291*3088717bSVictor Perevertkin 
292*3088717bSVictor Perevertkin     // 3. Retrieve information about special devices and hack flags.
293*3088717bSVictor Perevertkin     if (NT_SUCCESS(status))
294*3088717bSVictor Perevertkin     {
295*3088717bSVictor Perevertkin         DeviceRetrieveHackFlagsFromRegistry(deviceExtension);
296*3088717bSVictor Perevertkin         // scan for bad items.
297*3088717bSVictor Perevertkin         DeviceScanForSpecial(deviceExtension, CdRomBadItems, DeviceHackFlagsScan);
298*3088717bSVictor Perevertkin         // Check to see if it's a special device that needs special error process.
299*3088717bSVictor Perevertkin         DeviceScanSpecialDevices(deviceExtension);  // may send command to device
300*3088717bSVictor Perevertkin     }
301*3088717bSVictor Perevertkin 
302*3088717bSVictor Perevertkin     // 4. Initialize the hotplug information only after the ScanForSpecial routines,
303*3088717bSVictor Perevertkin     // as it relies upon the hack flags - deviceExtension->PrivateFdoData->HackFlags.
304*3088717bSVictor Perevertkin     if (NT_SUCCESS(status))
305*3088717bSVictor Perevertkin     {
306*3088717bSVictor Perevertkin         status = DeviceInitializeHotplugInfo(deviceExtension);
307*3088717bSVictor Perevertkin     }
308*3088717bSVictor Perevertkin 
309*3088717bSVictor Perevertkin     if (NT_SUCCESS(status))
310*3088717bSVictor Perevertkin     {
311*3088717bSVictor Perevertkin         // cache the device's inquiry data
312*3088717bSVictor Perevertkin         status = DeviceCacheDeviceInquiryData(deviceExtension);
313*3088717bSVictor Perevertkin         if (!NT_SUCCESS(status))
314*3088717bSVictor Perevertkin         {
315*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT,
316*3088717bSVictor Perevertkin                         "Failed to cache the device's inquiry data, failng %!STATUS!\n",
317*3088717bSVictor Perevertkin                         status
318*3088717bSVictor Perevertkin                         ));
319*3088717bSVictor Perevertkin         }
320*3088717bSVictor Perevertkin     }
321*3088717bSVictor Perevertkin 
322*3088717bSVictor Perevertkin     // 5. Initialize MMC context, media change notification stuff and read media capacity
323*3088717bSVictor Perevertkin     if (NT_SUCCESS(status))
324*3088717bSVictor Perevertkin     {
325*3088717bSVictor Perevertkin         status = DeviceInitializeMediaChangeDetection(deviceExtension);
326*3088717bSVictor Perevertkin     }
327*3088717bSVictor Perevertkin     if (NT_SUCCESS(status))
328*3088717bSVictor Perevertkin     {
329*3088717bSVictor Perevertkin         status = DeviceInitMmcContext(deviceExtension);
330*3088717bSVictor Perevertkin     }
331*3088717bSVictor Perevertkin     if (NT_SUCCESS(status))
332*3088717bSVictor Perevertkin     {
333*3088717bSVictor Perevertkin         status = DeviceInitializeZPODD(deviceExtension);
334*3088717bSVictor Perevertkin     }
335*3088717bSVictor Perevertkin     if (NT_SUCCESS(status))
336*3088717bSVictor Perevertkin     {
337*3088717bSVictor Perevertkin         // Do READ CAPACITY. This SCSI command returns the last sector address
338*3088717bSVictor Perevertkin         // on the device and the bytes per sector. These are used to calculate
339*3088717bSVictor Perevertkin         // the drive capacity in bytes.
340*3088717bSVictor Perevertkin         status = MediaReadCapacity(Device);
341*3088717bSVictor Perevertkin 
342*3088717bSVictor Perevertkin         // If READ CAPACITY succeeded, we can safely conclude that there is a media present
343*3088717bSVictor Perevertkin         if (NT_SUCCESS(status))
344*3088717bSVictor Perevertkin         {
345*3088717bSVictor Perevertkin             DeviceSetMediaChangeStateEx(deviceExtension,
346*3088717bSVictor Perevertkin                                         MediaPresent,
347*3088717bSVictor Perevertkin                                         NULL);
348*3088717bSVictor Perevertkin         }
349*3088717bSVictor Perevertkin 
350*3088717bSVictor Perevertkin         // READ CAPACITY is not critical for init, ignore all errors occuring during its execution
351*3088717bSVictor Perevertkin         status = STATUS_SUCCESS;
352*3088717bSVictor Perevertkin     }
353*3088717bSVictor Perevertkin 
354*3088717bSVictor Perevertkin     // 6. Perform DVD-specific initialization
355*3088717bSVictor Perevertkin     if (NT_SUCCESS(status))
356*3088717bSVictor Perevertkin     {
357*3088717bSVictor Perevertkin         status = DeviceInitializeDvd(Device);
358*3088717bSVictor Perevertkin     }
359*3088717bSVictor Perevertkin 
360*3088717bSVictor Perevertkin     // 7. Miscellaneous initialization actions
361*3088717bSVictor Perevertkin     if (NT_SUCCESS(status))
362*3088717bSVictor Perevertkin     {
363*3088717bSVictor Perevertkin         if (deviceExtension->PrivateFdoData != NULL)
364*3088717bSVictor Perevertkin         {
365*3088717bSVictor Perevertkin             deviceExtension->PrivateFdoData->Perf.OriginalSrbFlags = deviceExtension->SrbFlags;
366*3088717bSVictor Perevertkin         }
367*3088717bSVictor Perevertkin 
368*3088717bSVictor Perevertkin         if (deviceExtension->DeviceAdditionalData.Mmc.IsWriter)
369*3088717bSVictor Perevertkin         {
370*3088717bSVictor Perevertkin             // OPC can really take this long per IMAPIv1 timeout....
371*3088717bSVictor Perevertkin             deviceExtension->TimeOutValue = max(deviceExtension->TimeOutValue, SCSI_CDROM_OPC_TIMEOUT);
372*3088717bSVictor Perevertkin         }
373*3088717bSVictor Perevertkin     }
374*3088717bSVictor Perevertkin 
375*3088717bSVictor Perevertkin     // 8. Enable the main timer, create ARC name as needed
376*3088717bSVictor Perevertkin     if (NT_SUCCESS(status))
377*3088717bSVictor Perevertkin     {
378*3088717bSVictor Perevertkin         // Device successfully added and initialized, increase CdRomCount.
379*3088717bSVictor Perevertkin         IoGetConfigurationInformation()->CdRomCount++;
380*3088717bSVictor Perevertkin 
381*3088717bSVictor Perevertkin         deviceExtension->IsInitialized = TRUE;
382*3088717bSVictor Perevertkin 
383*3088717bSVictor Perevertkin         DeviceEnableMainTimer(deviceExtension);
384*3088717bSVictor Perevertkin 
385*3088717bSVictor Perevertkin     }
386*3088717bSVictor Perevertkin 
387*3088717bSVictor Perevertkin #if (NTDDI_VERSION >= NTDDI_WIN8)
388*3088717bSVictor Perevertkin     // 9. Set volume interface properties
389*3088717bSVictor Perevertkin     if (NT_SUCCESS(status))
390*3088717bSVictor Perevertkin     {
391*3088717bSVictor Perevertkin         BOOLEAN isCritical = FALSE;
392*3088717bSVictor Perevertkin         BOOLEAN isPortable = FALSE;
393*3088717bSVictor Perevertkin         BOOLEAN isRemovable = TEST_FLAG(deviceExtension->DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA);
394*3088717bSVictor Perevertkin         DEVPROP_BOOLEAN propCritical = DEVPROP_FALSE;
395*3088717bSVictor Perevertkin         DEVPROP_BOOLEAN propPortable = DEVPROP_FALSE;
396*3088717bSVictor Perevertkin         DEVPROP_BOOLEAN propRemovable = DEVPROP_FALSE;
397*3088717bSVictor Perevertkin 
398*3088717bSVictor Perevertkin         status = DeviceIsPortable(deviceExtension, &isPortable);
399*3088717bSVictor Perevertkin 
400*3088717bSVictor Perevertkin         if (NT_SUCCESS(status))
401*3088717bSVictor Perevertkin         {
402*3088717bSVictor Perevertkin             if (isPortable) {
403*3088717bSVictor Perevertkin                 SET_FLAG(deviceExtension->DeviceObject->Characteristics, FILE_PORTABLE_DEVICE);
404*3088717bSVictor Perevertkin             }
405*3088717bSVictor Perevertkin 
406*3088717bSVictor Perevertkin             propPortable = isPortable ? DEVPROP_TRUE : DEVPROP_FALSE;
407*3088717bSVictor Perevertkin 
408*3088717bSVictor Perevertkin             status = IoSetDeviceInterfacePropertyData(&deviceExtension->MountedDeviceInterfaceName,
409*3088717bSVictor Perevertkin                                                       &DEVPKEY_Storage_Portable,
410*3088717bSVictor Perevertkin                                                       0,
411*3088717bSVictor Perevertkin                                                       0,
412*3088717bSVictor Perevertkin                                                       DEVPROP_TYPE_BOOLEAN,
413*3088717bSVictor Perevertkin                                                       sizeof(DEVPROP_BOOLEAN),
414*3088717bSVictor Perevertkin                                                       &propPortable);
415*3088717bSVictor Perevertkin         }
416*3088717bSVictor Perevertkin 
417*3088717bSVictor Perevertkin         if (NT_SUCCESS(status))
418*3088717bSVictor Perevertkin         {
419*3088717bSVictor Perevertkin             propRemovable = isRemovable ? DEVPROP_TRUE : DEVPROP_FALSE;
420*3088717bSVictor Perevertkin 
421*3088717bSVictor Perevertkin             status = IoSetDeviceInterfacePropertyData(&deviceExtension->MountedDeviceInterfaceName,
422*3088717bSVictor Perevertkin                                                       &DEVPKEY_Storage_Removable_Media,
423*3088717bSVictor Perevertkin                                                       0,
424*3088717bSVictor Perevertkin                                                       0,
425*3088717bSVictor Perevertkin                                                       DEVPROP_TYPE_BOOLEAN,
426*3088717bSVictor Perevertkin                                                       sizeof(DEVPROP_BOOLEAN),
427*3088717bSVictor Perevertkin                                                       &propRemovable);
428*3088717bSVictor Perevertkin         }
429*3088717bSVictor Perevertkin 
430*3088717bSVictor Perevertkin         if (NT_SUCCESS(status))
431*3088717bSVictor Perevertkin         {
432*3088717bSVictor Perevertkin             isCritical = TEST_FLAG(deviceExtension->DeviceObject->Flags,
433*3088717bSVictor Perevertkin                                    (DO_SYSTEM_SYSTEM_PARTITION |
434*3088717bSVictor Perevertkin                                     DO_SYSTEM_BOOT_PARTITION   |
435*3088717bSVictor Perevertkin                                     DO_SYSTEM_CRITICAL_PARTITION));
436*3088717bSVictor Perevertkin 
437*3088717bSVictor Perevertkin             propCritical = isCritical ? DEVPROP_TRUE : DEVPROP_FALSE;
438*3088717bSVictor Perevertkin 
439*3088717bSVictor Perevertkin             status = IoSetDeviceInterfacePropertyData(&deviceExtension->MountedDeviceInterfaceName,
440*3088717bSVictor Perevertkin                                                       &DEVPKEY_Storage_System_Critical,
441*3088717bSVictor Perevertkin                                                       0,
442*3088717bSVictor Perevertkin                                                       0,
443*3088717bSVictor Perevertkin                                                       DEVPROP_TYPE_BOOLEAN,
444*3088717bSVictor Perevertkin                                                       sizeof(DEVPROP_BOOLEAN),
445*3088717bSVictor Perevertkin                                                       &propCritical);
446*3088717bSVictor Perevertkin         }
447*3088717bSVictor Perevertkin 
448*3088717bSVictor Perevertkin     }
449*3088717bSVictor Perevertkin #endif
450*3088717bSVictor Perevertkin 
451*3088717bSVictor Perevertkin     return status;
452*3088717bSVictor Perevertkin }
453*3088717bSVictor Perevertkin 
454*3088717bSVictor Perevertkin 
_IRQL_requires_max_(APC_LEVEL)455*3088717bSVictor Perevertkin _IRQL_requires_max_(APC_LEVEL)
456*3088717bSVictor Perevertkin NTSTATUS
457*3088717bSVictor Perevertkin DeviceInitReleaseQueueContext(
458*3088717bSVictor Perevertkin     _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
459*3088717bSVictor Perevertkin     )
460*3088717bSVictor Perevertkin /*++
461*3088717bSVictor Perevertkin 
462*3088717bSVictor Perevertkin Routine Description:
463*3088717bSVictor Perevertkin 
464*3088717bSVictor Perevertkin     Part of device initialize routine. Initialize ReleaseQueue related stuff.
465*3088717bSVictor Perevertkin 
466*3088717bSVictor Perevertkin Arguments:
467*3088717bSVictor Perevertkin 
468*3088717bSVictor Perevertkin     DeviceExtension - device extension of WDFDEVICE.
469*3088717bSVictor Perevertkin 
470*3088717bSVictor Perevertkin Return Value:
471*3088717bSVictor Perevertkin 
472*3088717bSVictor Perevertkin     NTSTATUS
473*3088717bSVictor Perevertkin 
474*3088717bSVictor Perevertkin --*/
475*3088717bSVictor Perevertkin {
476*3088717bSVictor Perevertkin     NTSTATUS                status = STATUS_SUCCESS;
477*3088717bSVictor Perevertkin     WDF_OBJECT_ATTRIBUTES   attributes;
478*3088717bSVictor Perevertkin 
479*3088717bSVictor Perevertkin     PAGED_CODE();
480*3088717bSVictor Perevertkin 
481*3088717bSVictor Perevertkin     WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes,
482*3088717bSVictor Perevertkin                                             CDROM_REQUEST_CONTEXT);
483*3088717bSVictor Perevertkin     attributes.ParentObject = DeviceExtension->Device;
484*3088717bSVictor Perevertkin 
485*3088717bSVictor Perevertkin     status = WdfRequestCreate(&attributes,
486*3088717bSVictor Perevertkin                               DeviceExtension->IoTarget,
487*3088717bSVictor Perevertkin                               &(DeviceExtension->ReleaseQueueRequest));
488*3088717bSVictor Perevertkin 
489*3088717bSVictor Perevertkin     if (!NT_SUCCESS(status))
490*3088717bSVictor Perevertkin     {
491*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP,  "Cannot create the release queue request\n"));
492*3088717bSVictor Perevertkin 
493*3088717bSVictor Perevertkin         return status;
494*3088717bSVictor Perevertkin     }
495*3088717bSVictor Perevertkin 
496*3088717bSVictor Perevertkin     // Initialize ReleaseQueueInputMemory, a wrapper around ReleaseQueueSrb
497*3088717bSVictor Perevertkin     WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
498*3088717bSVictor Perevertkin     attributes.ParentObject = DeviceExtension->ReleaseQueueRequest;
499*3088717bSVictor Perevertkin 
500*3088717bSVictor Perevertkin     status = WdfMemoryCreatePreallocated(&attributes,
501*3088717bSVictor Perevertkin                                          &DeviceExtension->ReleaseQueueSrb,
502*3088717bSVictor Perevertkin                                          sizeof(SCSI_REQUEST_BLOCK),
503*3088717bSVictor Perevertkin                                          &DeviceExtension->ReleaseQueueInputMemory);
504*3088717bSVictor Perevertkin     if (!NT_SUCCESS(status))
505*3088717bSVictor Perevertkin     {
506*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP,  "Failed to allocate ReleaseQueueSrb.\n"));
507*3088717bSVictor Perevertkin 
508*3088717bSVictor Perevertkin         return status;
509*3088717bSVictor Perevertkin     }
510*3088717bSVictor Perevertkin 
511*3088717bSVictor Perevertkin     // Preformat the release queue request here to ensure that this call will never
512*3088717bSVictor Perevertkin     // fail during an actual release of the queue.
513*3088717bSVictor Perevertkin     if (NT_SUCCESS(status))
514*3088717bSVictor Perevertkin     {
515*3088717bSVictor Perevertkin         status = WdfIoTargetFormatRequestForInternalIoctlOthers(DeviceExtension->IoTarget,
516*3088717bSVictor Perevertkin                                                                 DeviceExtension->ReleaseQueueRequest,
517*3088717bSVictor Perevertkin                                                                 IOCTL_SCSI_EXECUTE_NONE,
518*3088717bSVictor Perevertkin                                                                 DeviceExtension->ReleaseQueueInputMemory,
519*3088717bSVictor Perevertkin                                                                 NULL,
520*3088717bSVictor Perevertkin                                                                 NULL,
521*3088717bSVictor Perevertkin                                                                 NULL,
522*3088717bSVictor Perevertkin                                                                 NULL,
523*3088717bSVictor Perevertkin                                                                 NULL);
524*3088717bSVictor Perevertkin     }
525*3088717bSVictor Perevertkin 
526*3088717bSVictor Perevertkin     // Set a CompletionRoutine callback function for ReleaseQueueRequest.
527*3088717bSVictor Perevertkin     if (NT_SUCCESS(status))
528*3088717bSVictor Perevertkin     {
529*3088717bSVictor Perevertkin         WdfRequestSetCompletionRoutine(DeviceExtension->ReleaseQueueRequest,
530*3088717bSVictor Perevertkin                                        DeviceReleaseQueueCompletion,
531*3088717bSVictor Perevertkin                                        DeviceExtension->Device);
532*3088717bSVictor Perevertkin     }
533*3088717bSVictor Perevertkin 
534*3088717bSVictor Perevertkin     // Create a spinlock for ReleaseQueueRequest
535*3088717bSVictor Perevertkin     WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
536*3088717bSVictor Perevertkin     attributes.ParentObject = DeviceExtension->Device;
537*3088717bSVictor Perevertkin 
538*3088717bSVictor Perevertkin     status = WdfSpinLockCreate(&attributes,
539*3088717bSVictor Perevertkin                                &(DeviceExtension->ReleaseQueueSpinLock));
540*3088717bSVictor Perevertkin 
541*3088717bSVictor Perevertkin     if (!NT_SUCCESS(status))
542*3088717bSVictor Perevertkin     {
543*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP,
544*3088717bSVictor Perevertkin                     "DeviceInitReleaseQueueContext: Cannot create the release queue spinlock\n"));
545*3088717bSVictor Perevertkin 
546*3088717bSVictor Perevertkin         return status;
547*3088717bSVictor Perevertkin     }
548*3088717bSVictor Perevertkin 
549*3088717bSVictor Perevertkin     // Initialize miscellaneous ReleaseQueue related fields
550*3088717bSVictor Perevertkin     DeviceExtension->ReleaseQueueNeeded = FALSE;
551*3088717bSVictor Perevertkin     DeviceExtension->ReleaseQueueInProgress = FALSE;
552*3088717bSVictor Perevertkin     DeviceExtension->ReleaseQueueSrb.Length = sizeof(SCSI_REQUEST_BLOCK);
553*3088717bSVictor Perevertkin 
554*3088717bSVictor Perevertkin     return status;
555*3088717bSVictor Perevertkin }
556*3088717bSVictor Perevertkin 
_IRQL_requires_max_(APC_LEVEL)557*3088717bSVictor Perevertkin _IRQL_requires_max_(APC_LEVEL)
558*3088717bSVictor Perevertkin NTSTATUS
559*3088717bSVictor Perevertkin DeviceInitPowerContext(
560*3088717bSVictor Perevertkin     _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
561*3088717bSVictor Perevertkin     )
562*3088717bSVictor Perevertkin /*++
563*3088717bSVictor Perevertkin 
564*3088717bSVictor Perevertkin Routine Description:
565*3088717bSVictor Perevertkin 
566*3088717bSVictor Perevertkin     Part of device initialize routine. Initialize PowerContext related stuff.
567*3088717bSVictor Perevertkin 
568*3088717bSVictor Perevertkin Arguments:
569*3088717bSVictor Perevertkin 
570*3088717bSVictor Perevertkin     DeviceExtension - device extension of WDFDEVICE.
571*3088717bSVictor Perevertkin 
572*3088717bSVictor Perevertkin Return Value:
573*3088717bSVictor Perevertkin 
574*3088717bSVictor Perevertkin     NTSTATUS
575*3088717bSVictor Perevertkin 
576*3088717bSVictor Perevertkin --*/
577*3088717bSVictor Perevertkin {
578*3088717bSVictor Perevertkin     NTSTATUS                status = STATUS_SUCCESS;
579*3088717bSVictor Perevertkin     WDF_OBJECT_ATTRIBUTES   attributes;
580*3088717bSVictor Perevertkin 
581*3088717bSVictor Perevertkin     PAGED_CODE();
582*3088717bSVictor Perevertkin 
583*3088717bSVictor Perevertkin     // create request object for Power operations
584*3088717bSVictor Perevertkin 
585*3088717bSVictor Perevertkin     WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes,
586*3088717bSVictor Perevertkin                                             CDROM_REQUEST_CONTEXT);
587*3088717bSVictor Perevertkin     attributes.ParentObject = DeviceExtension->Device;
588*3088717bSVictor Perevertkin 
589*3088717bSVictor Perevertkin     status = WdfRequestCreate(&attributes,
590*3088717bSVictor Perevertkin                               DeviceExtension->IoTarget,
591*3088717bSVictor Perevertkin                               &(DeviceExtension->PowerContext.PowerRequest) );
592*3088717bSVictor Perevertkin 
593*3088717bSVictor Perevertkin     if (!NT_SUCCESS(status))
594*3088717bSVictor Perevertkin     {
595*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP,  "Cannot create the power request object.\n"));
596*3088717bSVictor Perevertkin 
597*3088717bSVictor Perevertkin         return status;
598*3088717bSVictor Perevertkin     }
599*3088717bSVictor Perevertkin 
600*3088717bSVictor Perevertkin     // Preformat the power request. With this being done, we never need to worry about
601*3088717bSVictor Perevertkin     // WdfIoTargetFormatRequestForInternalIoctlOthers ever failing later.
602*3088717bSVictor Perevertkin     status = WdfIoTargetFormatRequestForInternalIoctlOthers(DeviceExtension->IoTarget,
603*3088717bSVictor Perevertkin                                                             DeviceExtension->PowerContext.PowerRequest,
604*3088717bSVictor Perevertkin                                                             IOCTL_SCSI_EXECUTE_IN,
605*3088717bSVictor Perevertkin                                                             NULL, NULL,
606*3088717bSVictor Perevertkin                                                             NULL, NULL,
607*3088717bSVictor Perevertkin                                                             NULL, NULL);
608*3088717bSVictor Perevertkin     return status;
609*3088717bSVictor Perevertkin }
610*3088717bSVictor Perevertkin 
_IRQL_requires_max_(APC_LEVEL)611*3088717bSVictor Perevertkin _IRQL_requires_max_(APC_LEVEL)
612*3088717bSVictor Perevertkin NTSTATUS
613*3088717bSVictor Perevertkin DeviceCreateWellKnownName(
614*3088717bSVictor Perevertkin     _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
615*3088717bSVictor Perevertkin     )
616*3088717bSVictor Perevertkin /*++
617*3088717bSVictor Perevertkin 
618*3088717bSVictor Perevertkin Routine Description:
619*3088717bSVictor Perevertkin 
620*3088717bSVictor Perevertkin     This routine creates a symbolic link to the cdrom device object
621*3088717bSVictor Perevertkin     under \dosdevices.  The number of the cdrom device does not neccessarily
622*3088717bSVictor Perevertkin     match between \dosdevices and \device, but usually will be the same.
623*3088717bSVictor Perevertkin 
624*3088717bSVictor Perevertkin     Saves the buffer
625*3088717bSVictor Perevertkin 
626*3088717bSVictor Perevertkin Arguments:
627*3088717bSVictor Perevertkin 
628*3088717bSVictor Perevertkin     DeviceObject -
629*3088717bSVictor Perevertkin 
630*3088717bSVictor Perevertkin Return Value:
631*3088717bSVictor Perevertkin 
632*3088717bSVictor Perevertkin     NTSTATUS
633*3088717bSVictor Perevertkin 
634*3088717bSVictor Perevertkin --*/
635*3088717bSVictor Perevertkin {
636*3088717bSVictor Perevertkin     NTSTATUS        status = STATUS_SUCCESS;
637*3088717bSVictor Perevertkin     UNICODE_STRING  unicodeLinkName = {0};
638*3088717bSVictor Perevertkin     WCHAR           wideLinkName[64] = {0};
639*3088717bSVictor Perevertkin     PWCHAR          savedName;
640*3088717bSVictor Perevertkin 
641*3088717bSVictor Perevertkin     LONG            cdromNumber = DeviceExtension->DeviceNumber;
642*3088717bSVictor Perevertkin 
643*3088717bSVictor Perevertkin     PAGED_CODE();
644*3088717bSVictor Perevertkin 
645*3088717bSVictor Perevertkin     // if already linked, assert then return
646*3088717bSVictor Perevertkin     if (DeviceExtension->DeviceAdditionalData.WellKnownName.Buffer != NULL)
647*3088717bSVictor Perevertkin     {
648*3088717bSVictor Perevertkin 
649*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT,
650*3088717bSVictor Perevertkin                     "DeviceCreateWellKnownName: link already exists %p\n",
651*3088717bSVictor Perevertkin                     DeviceExtension->DeviceAdditionalData.WellKnownName.Buffer));
652*3088717bSVictor Perevertkin 
653*3088717bSVictor Perevertkin         NT_ASSERT(FALSE);
654*3088717bSVictor Perevertkin 
655*3088717bSVictor Perevertkin         return STATUS_UNSUCCESSFUL;
656*3088717bSVictor Perevertkin     }
657*3088717bSVictor Perevertkin 
658*3088717bSVictor Perevertkin     // find an unused CdRomNN to link to.
659*3088717bSVictor Perevertkin     // It's doing this way because the same might be used for other device in another driver.
660*3088717bSVictor Perevertkin     do
661*3088717bSVictor Perevertkin     {
662*3088717bSVictor Perevertkin         status = RtlStringCchPrintfW((NTSTRSAFE_PWSTR)wideLinkName,
663*3088717bSVictor Perevertkin                                      RTL_NUMBER_OF(wideLinkName),
664*3088717bSVictor Perevertkin                                      L"\\DosDevices\\CdRom%d",
665*3088717bSVictor Perevertkin                                      cdromNumber);
666*3088717bSVictor Perevertkin         if (!NT_SUCCESS(status))
667*3088717bSVictor Perevertkin         {
668*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT,
669*3088717bSVictor Perevertkin                         "DeviceCreateWellKnownName: Format symbolic link failed with error: 0x%X\n", status));
670*3088717bSVictor Perevertkin             return status;
671*3088717bSVictor Perevertkin         }
672*3088717bSVictor Perevertkin 
673*3088717bSVictor Perevertkin         RtlInitUnicodeString(&unicodeLinkName, wideLinkName);
674*3088717bSVictor Perevertkin 
675*3088717bSVictor Perevertkin         status = WdfDeviceCreateSymbolicLink(DeviceExtension->Device,
676*3088717bSVictor Perevertkin                                              &unicodeLinkName);
677*3088717bSVictor Perevertkin 
678*3088717bSVictor Perevertkin         cdromNumber++;
679*3088717bSVictor Perevertkin 
680*3088717bSVictor Perevertkin     } while((status == STATUS_OBJECT_NAME_COLLISION) ||
681*3088717bSVictor Perevertkin             (status == STATUS_OBJECT_NAME_EXISTS));
682*3088717bSVictor Perevertkin 
683*3088717bSVictor Perevertkin     if (!NT_SUCCESS(status))
684*3088717bSVictor Perevertkin     {
685*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT,
686*3088717bSVictor Perevertkin                     "DeviceCreateWellKnownName: Error %lx linking %wZ to "
687*3088717bSVictor Perevertkin                     "device %wZ\n",
688*3088717bSVictor Perevertkin                     status,
689*3088717bSVictor Perevertkin                     &unicodeLinkName,
690*3088717bSVictor Perevertkin                     &(DeviceExtension->DeviceName)));
691*3088717bSVictor Perevertkin         return status;
692*3088717bSVictor Perevertkin     }
693*3088717bSVictor Perevertkin 
694*3088717bSVictor Perevertkin     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
695*3088717bSVictor Perevertkin                 "DeviceCreateWellKnownName: successfully linked %wZ "
696*3088717bSVictor Perevertkin                 "to device %wZ\n",
697*3088717bSVictor Perevertkin                 &unicodeLinkName,
698*3088717bSVictor Perevertkin                 &(DeviceExtension->DeviceName)));
699*3088717bSVictor Perevertkin 
700*3088717bSVictor Perevertkin     // Save away the symbolic link name in the driver data block.  We need
701*3088717bSVictor Perevertkin     // it so we can delete the link when the device is removed.
702*3088717bSVictor Perevertkin     savedName = ExAllocatePoolWithTag(PagedPool,
703*3088717bSVictor Perevertkin                                       unicodeLinkName.MaximumLength,
704*3088717bSVictor Perevertkin                                       CDROM_TAG_STRINGS);
705*3088717bSVictor Perevertkin 
706*3088717bSVictor Perevertkin     if (savedName == NULL)
707*3088717bSVictor Perevertkin     {
708*3088717bSVictor Perevertkin         // Test Note: test path should excise here to see if the symbolic is deleted by framework.
709*3088717bSVictor Perevertkin         // IoDeleteSymbolicLink(&unicodeLinkName);
710*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT,
711*3088717bSVictor Perevertkin                     "DeviceCreateWellKnownName: unable to allocate memory.\n"));
712*3088717bSVictor Perevertkin 
713*3088717bSVictor Perevertkin         return STATUS_INSUFFICIENT_RESOURCES;
714*3088717bSVictor Perevertkin     }
715*3088717bSVictor Perevertkin 
716*3088717bSVictor Perevertkin     RtlZeroMemory(savedName, unicodeLinkName.MaximumLength);
717*3088717bSVictor Perevertkin     RtlCopyMemory(savedName, unicodeLinkName.Buffer, unicodeLinkName.MaximumLength);
718*3088717bSVictor Perevertkin 
719*3088717bSVictor Perevertkin     RtlInitUnicodeString(&(DeviceExtension->DeviceAdditionalData.WellKnownName), savedName);
720*3088717bSVictor Perevertkin 
721*3088717bSVictor Perevertkin     // the name was saved and the link created
722*3088717bSVictor Perevertkin 
723*3088717bSVictor Perevertkin     return STATUS_SUCCESS;
724*3088717bSVictor Perevertkin }
725*3088717bSVictor Perevertkin 
_IRQL_requires_max_(PASSIVE_LEVEL)726*3088717bSVictor Perevertkin _IRQL_requires_max_(PASSIVE_LEVEL)
727*3088717bSVictor Perevertkin NTSTATUS
728*3088717bSVictor Perevertkin DeviceRetrieveScsiAddress(
729*3088717bSVictor Perevertkin     _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
730*3088717bSVictor Perevertkin     _In_ PSCSI_ADDRESS           ScsiAddress
731*3088717bSVictor Perevertkin     )
732*3088717bSVictor Perevertkin /*++
733*3088717bSVictor Perevertkin 
734*3088717bSVictor Perevertkin Routine Description:
735*3088717bSVictor Perevertkin 
736*3088717bSVictor Perevertkin     retrieve SCSI address information and put into device extension
737*3088717bSVictor Perevertkin 
738*3088717bSVictor Perevertkin Arguments:
739*3088717bSVictor Perevertkin 
740*3088717bSVictor Perevertkin     DeviceExtension - device context.
741*3088717bSVictor Perevertkin     ScsiAddress - the buffer to put the scsi address info.
742*3088717bSVictor Perevertkin 
743*3088717bSVictor Perevertkin Return Value:
744*3088717bSVictor Perevertkin 
745*3088717bSVictor Perevertkin     NTSTATUS
746*3088717bSVictor Perevertkin 
747*3088717bSVictor Perevertkin --*/
748*3088717bSVictor Perevertkin {
749*3088717bSVictor Perevertkin     NTSTATUS                status;
750*3088717bSVictor Perevertkin     WDF_MEMORY_DESCRIPTOR   outputDescriptor;
751*3088717bSVictor Perevertkin 
752*3088717bSVictor Perevertkin     PAGED_CODE();
753*3088717bSVictor Perevertkin 
754*3088717bSVictor Perevertkin     if ((DeviceExtension == NULL) ||
755*3088717bSVictor Perevertkin         (ScsiAddress == NULL))
756*3088717bSVictor Perevertkin     {
757*3088717bSVictor Perevertkin         return STATUS_INVALID_PARAMETER;
758*3088717bSVictor Perevertkin     }
759*3088717bSVictor Perevertkin 
760*3088717bSVictor Perevertkin     //Get IOTARGET for sending request to port driver.
761*3088717bSVictor Perevertkin     WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&outputDescriptor,
762*3088717bSVictor Perevertkin                                       (PVOID)ScsiAddress,
763*3088717bSVictor Perevertkin                                       sizeof(SCSI_ADDRESS));
764*3088717bSVictor Perevertkin 
765*3088717bSVictor Perevertkin     status = WdfIoTargetSendIoctlSynchronously(DeviceExtension->IoTarget,
766*3088717bSVictor Perevertkin                                                NULL,
767*3088717bSVictor Perevertkin                                                IOCTL_SCSI_GET_ADDRESS,
768*3088717bSVictor Perevertkin                                                NULL,
769*3088717bSVictor Perevertkin                                                &outputDescriptor,
770*3088717bSVictor Perevertkin                                                NULL,
771*3088717bSVictor Perevertkin                                                NULL);
772*3088717bSVictor Perevertkin 
773*3088717bSVictor Perevertkin     if (!NT_SUCCESS(status))
774*3088717bSVictor Perevertkin     {
775*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT,
776*3088717bSVictor Perevertkin                     "DeviceRetrieveScsiAddress: Get Address failed %lx\n",
777*3088717bSVictor Perevertkin                     status));
778*3088717bSVictor Perevertkin     }
779*3088717bSVictor Perevertkin     else
780*3088717bSVictor Perevertkin     {
781*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT,
782*3088717bSVictor Perevertkin                     "GetAddress: Port %x, Path %x, Target %x, Lun %x\n",
783*3088717bSVictor Perevertkin                     ScsiAddress->PortNumber,
784*3088717bSVictor Perevertkin                     ScsiAddress->PathId,
785*3088717bSVictor Perevertkin                     ScsiAddress->TargetId,
786*3088717bSVictor Perevertkin                     ScsiAddress->Lun));
787*3088717bSVictor Perevertkin     }
788*3088717bSVictor Perevertkin 
789*3088717bSVictor Perevertkin     return status;
790*3088717bSVictor Perevertkin }
791*3088717bSVictor Perevertkin 
_IRQL_requires_max_(APC_LEVEL)792*3088717bSVictor Perevertkin _IRQL_requires_max_(APC_LEVEL)
793*3088717bSVictor Perevertkin NTSTATUS
794*3088717bSVictor Perevertkin DeviceInitAllocateBuffers(
795*3088717bSVictor Perevertkin     _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
796*3088717bSVictor Perevertkin     )
797*3088717bSVictor Perevertkin /*++
798*3088717bSVictor Perevertkin 
799*3088717bSVictor Perevertkin Routine Description:
800*3088717bSVictor Perevertkin 
801*3088717bSVictor Perevertkin     Part of device initialize routine.
802*3088717bSVictor Perevertkin     Allocate all buffers in Device Extension.
803*3088717bSVictor Perevertkin 
804*3088717bSVictor Perevertkin Arguments:
805*3088717bSVictor Perevertkin 
806*3088717bSVictor Perevertkin     DeviceExtension - device extension of WDFDEVICE.
807*3088717bSVictor Perevertkin 
808*3088717bSVictor Perevertkin Return Value:
809*3088717bSVictor Perevertkin 
810*3088717bSVictor Perevertkin     NTSTATUS
811*3088717bSVictor Perevertkin 
812*3088717bSVictor Perevertkin --*/
813*3088717bSVictor Perevertkin {
814*3088717bSVictor Perevertkin     NTSTATUS            status = STATUS_SUCCESS;
815*3088717bSVictor Perevertkin     PVOID               senseData = NULL;
816*3088717bSVictor Perevertkin 
817*3088717bSVictor Perevertkin     PAGED_CODE();
818*3088717bSVictor Perevertkin 
819*3088717bSVictor Perevertkin     // allocate a private extension for class data
820*3088717bSVictor Perevertkin     if (DeviceExtension->PrivateFdoData == NULL)
821*3088717bSVictor Perevertkin     {
822*3088717bSVictor Perevertkin         DeviceExtension->PrivateFdoData = ExAllocatePoolWithTag(NonPagedPoolNx,
823*3088717bSVictor Perevertkin                                                                 sizeof(CDROM_PRIVATE_FDO_DATA),
824*3088717bSVictor Perevertkin                                                                 CDROM_TAG_PRIVATE_DATA);
825*3088717bSVictor Perevertkin     }
826*3088717bSVictor Perevertkin 
827*3088717bSVictor Perevertkin     if (DeviceExtension->PrivateFdoData == NULL)
828*3088717bSVictor Perevertkin     {
829*3088717bSVictor Perevertkin         status = STATUS_INSUFFICIENT_RESOURCES;
830*3088717bSVictor Perevertkin     }
831*3088717bSVictor Perevertkin     else
832*3088717bSVictor Perevertkin     {
833*3088717bSVictor Perevertkin         // initialize the struct's various fields.
834*3088717bSVictor Perevertkin         RtlZeroMemory(DeviceExtension->PrivateFdoData, sizeof(CDROM_PRIVATE_FDO_DATA));
835*3088717bSVictor Perevertkin     }
836*3088717bSVictor Perevertkin 
837*3088717bSVictor Perevertkin     // Allocate request sense buffer.
838*3088717bSVictor Perevertkin     senseData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
839*3088717bSVictor Perevertkin                                       SENSE_BUFFER_SIZE,
840*3088717bSVictor Perevertkin                                       CDROM_TAG_SENSE_INFO);
841*3088717bSVictor Perevertkin 
842*3088717bSVictor Perevertkin     if (senseData == NULL)
843*3088717bSVictor Perevertkin     {
844*3088717bSVictor Perevertkin         // The buffer cannot be allocated.
845*3088717bSVictor Perevertkin         status = STATUS_INSUFFICIENT_RESOURCES;
846*3088717bSVictor Perevertkin     }
847*3088717bSVictor Perevertkin     else
848*3088717bSVictor Perevertkin     {
849*3088717bSVictor Perevertkin         // Set the sense data pointer in the device extension.
850*3088717bSVictor Perevertkin         DeviceExtension->SenseData = senseData;
851*3088717bSVictor Perevertkin     }
852*3088717bSVictor Perevertkin 
853*3088717bSVictor Perevertkin     // Allocate scratch buffer -- Must occur after determining
854*3088717bSVictor Perevertkin     // max transfer size, but before other CD specific detection
855*3088717bSVictor Perevertkin     // (which relies upon this buffer).
856*3088717bSVictor Perevertkin     if (!ScratchBuffer_Allocate(DeviceExtension))
857*3088717bSVictor Perevertkin     {
858*3088717bSVictor Perevertkin         status = STATUS_INSUFFICIENT_RESOURCES;
859*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT,
860*3088717bSVictor Perevertkin                     "Failed to allocate scratch buffer, failing  %!STATUS!\n",
861*3088717bSVictor Perevertkin                     status
862*3088717bSVictor Perevertkin                     ));
863*3088717bSVictor Perevertkin     }
864*3088717bSVictor Perevertkin 
865*3088717bSVictor Perevertkin     return status;
866*3088717bSVictor Perevertkin }
867*3088717bSVictor Perevertkin 
_IRQL_requires_max_(PASSIVE_LEVEL)868*3088717bSVictor Perevertkin _IRQL_requires_max_(PASSIVE_LEVEL)
869*3088717bSVictor Perevertkin NTSTATUS
870*3088717bSVictor Perevertkin DeviceRetrieveDescriptorsAndTransferLength(
871*3088717bSVictor Perevertkin     _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
872*3088717bSVictor Perevertkin     )
873*3088717bSVictor Perevertkin /*++
874*3088717bSVictor Perevertkin 
875*3088717bSVictor Perevertkin Routine Description:
876*3088717bSVictor Perevertkin 
877*3088717bSVictor Perevertkin     Part of device initialize routine.
878*3088717bSVictor Perevertkin     Retrieve Device Descriptor and Adaptor Descriptor.
879*3088717bSVictor Perevertkin 
880*3088717bSVictor Perevertkin Arguments:
881*3088717bSVictor Perevertkin 
882*3088717bSVictor Perevertkin     DeviceExtension - device extension of WDFDEVICE.
883*3088717bSVictor Perevertkin 
884*3088717bSVictor Perevertkin Return Value:
885*3088717bSVictor Perevertkin 
886*3088717bSVictor Perevertkin     NTSTATUS
887*3088717bSVictor Perevertkin 
888*3088717bSVictor Perevertkin --*/
889*3088717bSVictor Perevertkin {
890*3088717bSVictor Perevertkin     NTSTATUS            status = STATUS_SUCCESS;
891*3088717bSVictor Perevertkin     STORAGE_PROPERTY_ID propertyId;
892*3088717bSVictor Perevertkin 
893*3088717bSVictor Perevertkin     PAGED_CODE();
894*3088717bSVictor Perevertkin 
895*3088717bSVictor Perevertkin     if (NT_SUCCESS(status))
896*3088717bSVictor Perevertkin     {
897*3088717bSVictor Perevertkin         // Call port driver to get adapter capabilities.
898*3088717bSVictor Perevertkin         propertyId = StorageAdapterProperty;
899*3088717bSVictor Perevertkin 
900*3088717bSVictor Perevertkin         status = DeviceRetrieveDescriptor(DeviceExtension->Device,
901*3088717bSVictor Perevertkin                                           &propertyId,
902*3088717bSVictor Perevertkin                                           (PSTORAGE_DESCRIPTOR_HEADER*)&DeviceExtension->AdapterDescriptor);
903*3088717bSVictor Perevertkin     }
904*3088717bSVictor Perevertkin     if (NT_SUCCESS(status))
905*3088717bSVictor Perevertkin     {
906*3088717bSVictor Perevertkin         // Call port driver to get device descriptor.
907*3088717bSVictor Perevertkin         propertyId = StorageDeviceProperty;
908*3088717bSVictor Perevertkin 
909*3088717bSVictor Perevertkin         status = DeviceRetrieveDescriptor(DeviceExtension->Device,
910*3088717bSVictor Perevertkin                                           &propertyId,
911*3088717bSVictor Perevertkin                                           (PSTORAGE_DESCRIPTOR_HEADER*)&DeviceExtension->DeviceDescriptor);
912*3088717bSVictor Perevertkin     }
913*3088717bSVictor Perevertkin     if (NT_SUCCESS(status))
914*3088717bSVictor Perevertkin     {
915*3088717bSVictor Perevertkin         // Call port driver to get device power property.
916*3088717bSVictor Perevertkin         // Not all port drivers support this property, and it's not fatal if this query fails.
917*3088717bSVictor Perevertkin         propertyId = StorageDevicePowerProperty;
918*3088717bSVictor Perevertkin 
919*3088717bSVictor Perevertkin         (void) DeviceRetrieveDescriptor(DeviceExtension->Device,
920*3088717bSVictor Perevertkin                                         &propertyId,
921*3088717bSVictor Perevertkin                                         (PSTORAGE_DESCRIPTOR_HEADER*)&DeviceExtension->PowerDescriptor);
922*3088717bSVictor Perevertkin     }
923*3088717bSVictor Perevertkin 
924*3088717bSVictor Perevertkin     if (NT_SUCCESS(status))
925*3088717bSVictor Perevertkin     {
926*3088717bSVictor Perevertkin         // Determine the maximum page-aligned and non-page-aligned transfer
927*3088717bSVictor Perevertkin         // lengths here, so we needn't do this in common READ/WRITE code paths
928*3088717bSVictor Perevertkin 
929*3088717bSVictor Perevertkin         // start with the number of pages the adapter can support
930*3088717bSVictor Perevertkin         ULONG maxAlignedTransfer = DeviceExtension->AdapterDescriptor->MaximumPhysicalPages;
931*3088717bSVictor Perevertkin         ULONG maxUnalignedTransfer = DeviceExtension->AdapterDescriptor->MaximumPhysicalPages;
932*3088717bSVictor Perevertkin 
933*3088717bSVictor Perevertkin 
934*3088717bSVictor Perevertkin         // Unaligned buffers could cross a page boundary.
935*3088717bSVictor Perevertkin         if (maxUnalignedTransfer > 1)
936*3088717bSVictor Perevertkin         {
937*3088717bSVictor Perevertkin             maxUnalignedTransfer--;
938*3088717bSVictor Perevertkin         }
939*3088717bSVictor Perevertkin 
940*3088717bSVictor Perevertkin         // if we'd overflow multiplying by page size, just max out the
941*3088717bSVictor Perevertkin         // transfer length allowed by the number of pages limit.
942*3088717bSVictor Perevertkin         if (maxAlignedTransfer >= (((ULONG)-1) / PAGE_SIZE))
943*3088717bSVictor Perevertkin         {
944*3088717bSVictor Perevertkin             maxAlignedTransfer = (ULONG)-1;
945*3088717bSVictor Perevertkin         }
946*3088717bSVictor Perevertkin         else
947*3088717bSVictor Perevertkin         {
948*3088717bSVictor Perevertkin             maxAlignedTransfer *= PAGE_SIZE;
949*3088717bSVictor Perevertkin         }
950*3088717bSVictor Perevertkin 
951*3088717bSVictor Perevertkin         if (maxUnalignedTransfer >= (((ULONG)-1) / PAGE_SIZE))
952*3088717bSVictor Perevertkin         {
953*3088717bSVictor Perevertkin             maxUnalignedTransfer = (ULONG)-1;
954*3088717bSVictor Perevertkin         }
955*3088717bSVictor Perevertkin         else
956*3088717bSVictor Perevertkin         {
957*3088717bSVictor Perevertkin             maxUnalignedTransfer *= PAGE_SIZE;
958*3088717bSVictor Perevertkin         }
959*3088717bSVictor Perevertkin 
960*3088717bSVictor Perevertkin         // finally, take the smaller of the above and the adapter's
961*3088717bSVictor Perevertkin         // reported maximum number of bytes per transfer.
962*3088717bSVictor Perevertkin         maxAlignedTransfer   = min(maxAlignedTransfer,   DeviceExtension->AdapterDescriptor->MaximumTransferLength);
963*3088717bSVictor Perevertkin         maxUnalignedTransfer = min(maxUnalignedTransfer, DeviceExtension->AdapterDescriptor->MaximumTransferLength);
964*3088717bSVictor Perevertkin 
965*3088717bSVictor Perevertkin         // Make sure the values are reasonable and not zero.
966*3088717bSVictor Perevertkin         maxAlignedTransfer   = max(maxAlignedTransfer,   PAGE_SIZE);
967*3088717bSVictor Perevertkin         maxUnalignedTransfer = max(maxUnalignedTransfer, PAGE_SIZE);
968*3088717bSVictor Perevertkin 
969*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
970*3088717bSVictor Perevertkin                   "Device %p Max aligned/unaligned transfer size is %x/%x\n",
971*3088717bSVictor Perevertkin                   DeviceExtension->Device,
972*3088717bSVictor Perevertkin                   maxAlignedTransfer,
973*3088717bSVictor Perevertkin                   maxUnalignedTransfer
974*3088717bSVictor Perevertkin                   ));
975*3088717bSVictor Perevertkin         DeviceExtension->DeviceAdditionalData.MaxPageAlignedTransferBytes = maxAlignedTransfer;
976*3088717bSVictor Perevertkin         DeviceExtension->DeviceAdditionalData.MaxUnalignedTransferBytes = maxUnalignedTransfer;
977*3088717bSVictor Perevertkin     }
978*3088717bSVictor Perevertkin     else
979*3088717bSVictor Perevertkin     {
980*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP,  "DeviceRetrieveDescriptorsAndTransferLength failed %lx\n", status));
981*3088717bSVictor Perevertkin     }
982*3088717bSVictor Perevertkin 
983*3088717bSVictor Perevertkin     return status;
984*3088717bSVictor Perevertkin }
985*3088717bSVictor Perevertkin 
986*3088717bSVictor Perevertkin 
_IRQL_requires_max_(PASSIVE_LEVEL)987*3088717bSVictor Perevertkin _IRQL_requires_max_(PASSIVE_LEVEL)
988*3088717bSVictor Perevertkin NTSTATUS
989*3088717bSVictor Perevertkin DeviceRetrieveDescriptor(
990*3088717bSVictor Perevertkin     _In_ WDFDEVICE                              Device,
991*3088717bSVictor Perevertkin     _In_ PSTORAGE_PROPERTY_ID                   PropertyId,
992*3088717bSVictor Perevertkin     _Outptr_ PSTORAGE_DESCRIPTOR_HEADER*        Descriptor
993*3088717bSVictor Perevertkin     )
994*3088717bSVictor Perevertkin /*++
995*3088717bSVictor Perevertkin 
996*3088717bSVictor Perevertkin Routine Description:
997*3088717bSVictor Perevertkin 
998*3088717bSVictor Perevertkin     This routine will perform a query for the specified property id and will
999*3088717bSVictor Perevertkin     allocate a non-paged buffer to store the data in.  It is the responsibility
1000*3088717bSVictor Perevertkin     of the caller to ensure that this buffer is freed.
1001*3088717bSVictor Perevertkin 
1002*3088717bSVictor Perevertkin     This routine must be run at IRQL_PASSIVE_LEVEL
1003*3088717bSVictor Perevertkin 
1004*3088717bSVictor Perevertkin Arguments:
1005*3088717bSVictor Perevertkin 
1006*3088717bSVictor Perevertkin     Device - the device object
1007*3088717bSVictor Perevertkin     PropertyId - type of property to retrieve
1008*3088717bSVictor Perevertkin     Descriptor - buffer allocated in this function to hold the descriptor data
1009*3088717bSVictor Perevertkin 
1010*3088717bSVictor Perevertkin Return Value:
1011*3088717bSVictor Perevertkin 
1012*3088717bSVictor Perevertkin     status
1013*3088717bSVictor Perevertkin 
1014*3088717bSVictor Perevertkin --*/
1015*3088717bSVictor Perevertkin {
1016*3088717bSVictor Perevertkin     NTSTATUS                status;
1017*3088717bSVictor Perevertkin     WDF_MEMORY_DESCRIPTOR   memoryDescriptor;
1018*3088717bSVictor Perevertkin 
1019*3088717bSVictor Perevertkin     STORAGE_PROPERTY_QUERY  query = {0};
1020*3088717bSVictor Perevertkin     ULONG                   bufferLength = 0;
1021*3088717bSVictor Perevertkin 
1022*3088717bSVictor Perevertkin     PSTORAGE_DESCRIPTOR_HEADER  descriptor = NULL;
1023*3088717bSVictor Perevertkin     PCDROM_DEVICE_EXTENSION     deviceExtension = DeviceGetExtension(Device);
1024*3088717bSVictor Perevertkin 
1025*3088717bSVictor Perevertkin     PAGED_CODE();
1026*3088717bSVictor Perevertkin 
1027*3088717bSVictor Perevertkin     // Set the passed-in descriptor pointer to NULL as default
1028*3088717bSVictor Perevertkin     *Descriptor = NULL;
1029*3088717bSVictor Perevertkin 
1030*3088717bSVictor Perevertkin     // On the first pass we just want to get the first few
1031*3088717bSVictor Perevertkin     // bytes of the descriptor so we can read it's size
1032*3088717bSVictor Perevertkin     query.PropertyId = *PropertyId;
1033*3088717bSVictor Perevertkin     query.QueryType = PropertyStandardQuery;
1034*3088717bSVictor Perevertkin 
1035*3088717bSVictor Perevertkin     descriptor = (PVOID)&query;
1036*3088717bSVictor Perevertkin 
1037*3088717bSVictor Perevertkin     NT_ASSERT(sizeof(STORAGE_PROPERTY_QUERY) >= (sizeof(ULONG)*2));
1038*3088717bSVictor Perevertkin 
1039*3088717bSVictor Perevertkin     WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memoryDescriptor,
1040*3088717bSVictor Perevertkin                                       (PVOID)&query,
1041*3088717bSVictor Perevertkin                                       sizeof(STORAGE_PROPERTY_QUERY));
1042*3088717bSVictor Perevertkin 
1043*3088717bSVictor Perevertkin     status = WdfIoTargetSendIoctlSynchronously(deviceExtension->IoTarget,
1044*3088717bSVictor Perevertkin                                                NULL,
1045*3088717bSVictor Perevertkin                                                IOCTL_STORAGE_QUERY_PROPERTY,
1046*3088717bSVictor Perevertkin                                                &memoryDescriptor,
1047*3088717bSVictor Perevertkin                                                &memoryDescriptor,
1048*3088717bSVictor Perevertkin                                                NULL,
1049*3088717bSVictor Perevertkin                                                NULL);
1050*3088717bSVictor Perevertkin 
1051*3088717bSVictor Perevertkin     if(!NT_SUCCESS(status))
1052*3088717bSVictor Perevertkin     {
1053*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT,  "DeviceRetrieveDescriptor: error %lx trying to "
1054*3088717bSVictor Perevertkin                        "query properties #1\n", status));
1055*3088717bSVictor Perevertkin         return status;
1056*3088717bSVictor Perevertkin     }
1057*3088717bSVictor Perevertkin 
1058*3088717bSVictor Perevertkin     if (descriptor->Size == 0)
1059*3088717bSVictor Perevertkin     {
1060*3088717bSVictor Perevertkin         // This DebugPrint is to help third-party driver writers
1061*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT,  "DeviceRetrieveDescriptor: size returned was zero?! (status "
1062*3088717bSVictor Perevertkin                     "%x\n", status));
1063*3088717bSVictor Perevertkin         return STATUS_UNSUCCESSFUL;
1064*3088717bSVictor Perevertkin     }
1065*3088717bSVictor Perevertkin 
1066*3088717bSVictor Perevertkin     // This time we know how much data there is so we can
1067*3088717bSVictor Perevertkin     // allocate a buffer of the correct size
1068*3088717bSVictor Perevertkin     bufferLength = descriptor->Size;
1069*3088717bSVictor Perevertkin     NT_ASSERT(bufferLength >= sizeof(STORAGE_PROPERTY_QUERY));
1070*3088717bSVictor Perevertkin     bufferLength = max(bufferLength, sizeof(STORAGE_PROPERTY_QUERY));
1071*3088717bSVictor Perevertkin 
1072*3088717bSVictor Perevertkin     descriptor = ExAllocatePoolWithTag(NonPagedPoolNx, bufferLength, CDROM_TAG_DESCRIPTOR);
1073*3088717bSVictor Perevertkin 
1074*3088717bSVictor Perevertkin     if(descriptor == NULL)
1075*3088717bSVictor Perevertkin     {
1076*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT,  "DeviceRetrieveDescriptor: unable to memory for descriptor "
1077*3088717bSVictor Perevertkin                     "(%d bytes)\n", bufferLength));
1078*3088717bSVictor Perevertkin         return STATUS_INSUFFICIENT_RESOURCES;
1079*3088717bSVictor Perevertkin     }
1080*3088717bSVictor Perevertkin 
1081*3088717bSVictor Perevertkin     // setup the query again, as it was overwritten above
1082*3088717bSVictor Perevertkin     RtlZeroMemory(&query, sizeof(STORAGE_PROPERTY_QUERY));
1083*3088717bSVictor Perevertkin     query.PropertyId = *PropertyId;
1084*3088717bSVictor Perevertkin     query.QueryType = PropertyStandardQuery;
1085*3088717bSVictor Perevertkin 
1086*3088717bSVictor Perevertkin     // copy the input to the new outputbuffer
1087*3088717bSVictor Perevertkin     RtlCopyMemory(descriptor,
1088*3088717bSVictor Perevertkin                   &query,
1089*3088717bSVictor Perevertkin                   sizeof(STORAGE_PROPERTY_QUERY));
1090*3088717bSVictor Perevertkin 
1091*3088717bSVictor Perevertkin     WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memoryDescriptor,
1092*3088717bSVictor Perevertkin                                       (PVOID)descriptor,
1093*3088717bSVictor Perevertkin                                       bufferLength);
1094*3088717bSVictor Perevertkin 
1095*3088717bSVictor Perevertkin     status = WdfIoTargetSendIoctlSynchronously(deviceExtension->IoTarget,
1096*3088717bSVictor Perevertkin                                                NULL,
1097*3088717bSVictor Perevertkin                                                IOCTL_STORAGE_QUERY_PROPERTY,
1098*3088717bSVictor Perevertkin                                                &memoryDescriptor,
1099*3088717bSVictor Perevertkin                                                &memoryDescriptor,
1100*3088717bSVictor Perevertkin                                                NULL,
1101*3088717bSVictor Perevertkin                                                NULL);
1102*3088717bSVictor Perevertkin 
1103*3088717bSVictor Perevertkin     if(!NT_SUCCESS(status))
1104*3088717bSVictor Perevertkin     {
1105*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT,  "DeviceRetrieveDescriptor: error %lx trying to "
1106*3088717bSVictor Perevertkin                        "query properties #1\n", status));
1107*3088717bSVictor Perevertkin         FREE_POOL(descriptor);
1108*3088717bSVictor Perevertkin 
1109*3088717bSVictor Perevertkin         return status;
1110*3088717bSVictor Perevertkin     }
1111*3088717bSVictor Perevertkin 
1112*3088717bSVictor Perevertkin     // return the memory we've allocated to the caller
1113*3088717bSVictor Perevertkin     *Descriptor = descriptor;
1114*3088717bSVictor Perevertkin 
1115*3088717bSVictor Perevertkin     return status;
1116*3088717bSVictor Perevertkin } // end DeviceRetrieveDescriptor()
1117*3088717bSVictor Perevertkin 
_IRQL_requires_max_(PASSIVE_LEVEL)1118*3088717bSVictor Perevertkin _IRQL_requires_max_(PASSIVE_LEVEL)
1119*3088717bSVictor Perevertkin VOID
1120*3088717bSVictor Perevertkin DeviceRetrieveHackFlagsFromRegistry(
1121*3088717bSVictor Perevertkin     _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
1122*3088717bSVictor Perevertkin     )
1123*3088717bSVictor Perevertkin /*++
1124*3088717bSVictor Perevertkin 
1125*3088717bSVictor Perevertkin Routine Description:
1126*3088717bSVictor Perevertkin 
1127*3088717bSVictor Perevertkin     try to retrieve hack flages from registry and put the information in
1128*3088717bSVictor Perevertkin     device extension.
1129*3088717bSVictor Perevertkin 
1130*3088717bSVictor Perevertkin Arguments:
1131*3088717bSVictor Perevertkin 
1132*3088717bSVictor Perevertkin     DeviceExtension - the device context
1133*3088717bSVictor Perevertkin 
1134*3088717bSVictor Perevertkin Return Value:
1135*3088717bSVictor Perevertkin 
1136*3088717bSVictor Perevertkin     none
1137*3088717bSVictor Perevertkin 
1138*3088717bSVictor Perevertkin --*/
1139*3088717bSVictor Perevertkin {
1140*3088717bSVictor Perevertkin     NTSTATUS        status = STATUS_SUCCESS;
1141*3088717bSVictor Perevertkin     WDFKEY          hardwareKey = NULL;
1142*3088717bSVictor Perevertkin     WDFKEY          subKey = NULL;
1143*3088717bSVictor Perevertkin     ULONG           deviceHacks = 0;
1144*3088717bSVictor Perevertkin 
1145*3088717bSVictor Perevertkin     DECLARE_CONST_UNICODE_STRING(subKeyName, CLASSP_REG_SUBKEY_NAME);
1146*3088717bSVictor Perevertkin     DECLARE_CONST_UNICODE_STRING(valueName, CLASSP_REG_HACK_VALUE_NAME);
1147*3088717bSVictor Perevertkin 
1148*3088717bSVictor Perevertkin     PAGED_CODE();
1149*3088717bSVictor Perevertkin 
1150*3088717bSVictor Perevertkin     status = WdfDeviceOpenRegistryKey(DeviceExtension->Device,
1151*3088717bSVictor Perevertkin                                       PLUGPLAY_REGKEY_DEVICE,
1152*3088717bSVictor Perevertkin                                       KEY_READ,
1153*3088717bSVictor Perevertkin                                       WDF_NO_OBJECT_ATTRIBUTES,
1154*3088717bSVictor Perevertkin                                       &hardwareKey);
1155*3088717bSVictor Perevertkin     if (NT_SUCCESS(status))
1156*3088717bSVictor Perevertkin     {
1157*3088717bSVictor Perevertkin         status = WdfRegistryOpenKey(hardwareKey,
1158*3088717bSVictor Perevertkin                                     &subKeyName,
1159*3088717bSVictor Perevertkin                                     KEY_READ,
1160*3088717bSVictor Perevertkin                                     WDF_NO_OBJECT_ATTRIBUTES,
1161*3088717bSVictor Perevertkin                                     &subKey);
1162*3088717bSVictor Perevertkin 
1163*3088717bSVictor Perevertkin         if (NT_SUCCESS(status))
1164*3088717bSVictor Perevertkin         {
1165*3088717bSVictor Perevertkin             status = WdfRegistryQueryULong(subKey,
1166*3088717bSVictor Perevertkin                                            &valueName,
1167*3088717bSVictor Perevertkin                                            &deviceHacks);
1168*3088717bSVictor Perevertkin             if (NT_SUCCESS(status))
1169*3088717bSVictor Perevertkin             {
1170*3088717bSVictor Perevertkin                 // remove unknown values and save...
1171*3088717bSVictor Perevertkin                 CLEAR_FLAG(deviceHacks, FDO_HACK_INVALID_FLAGS);
1172*3088717bSVictor Perevertkin                 SET_FLAG(DeviceExtension->PrivateFdoData->HackFlags, deviceHacks);
1173*3088717bSVictor Perevertkin             }
1174*3088717bSVictor Perevertkin 
1175*3088717bSVictor Perevertkin             WdfRegistryClose(subKey);
1176*3088717bSVictor Perevertkin         }
1177*3088717bSVictor Perevertkin 
1178*3088717bSVictor Perevertkin         WdfRegistryClose(hardwareKey);
1179*3088717bSVictor Perevertkin     }
1180*3088717bSVictor Perevertkin 
1181*3088717bSVictor Perevertkin 
1182*3088717bSVictor Perevertkin     //
1183*3088717bSVictor Perevertkin     // we should modify the system hive to include another key for us to grab
1184*3088717bSVictor Perevertkin     // settings from.  in this case:  Classpnp\HackFlags
1185*3088717bSVictor Perevertkin     //
1186*3088717bSVictor Perevertkin     // the use of a DWORD value for the HackFlags allows 32 hacks w/o
1187*3088717bSVictor Perevertkin     // significant use of the registry, and also reduces OEM exposure.
1188*3088717bSVictor Perevertkin     //
1189*3088717bSVictor Perevertkin     // definition of bit flags:
1190*3088717bSVictor Perevertkin     //   0x00000001 -- Device succeeds PREVENT_MEDIUM_REMOVAL, but
1191*3088717bSVictor Perevertkin     //                 cannot actually prevent removal.
1192*3088717bSVictor Perevertkin     //   0x00000002 -- Device hard-hangs or times out for GESN requests.
1193*3088717bSVictor Perevertkin     //   0x00000008 -- Device does not support RESERVE(6) and RELEASE(6).
1194*3088717bSVictor Perevertkin     //   0x00000010 -- Device may incorrecly report operational changes in GESN.
1195*3088717bSVictor Perevertkin     //   0x00000020 -- Device does not support streaming READ(12) / WRITE(12).
1196*3088717bSVictor Perevertkin     //   0x00000040 -- Device does not support asynchronous notification.
1197*3088717bSVictor Perevertkin     //   0xffffff80 -- Currently reserved, may be used later.
1198*3088717bSVictor Perevertkin     //
1199*3088717bSVictor Perevertkin 
1200*3088717bSVictor Perevertkin     return;
1201*3088717bSVictor Perevertkin }
1202*3088717bSVictor Perevertkin 
_IRQL_requires_max_(APC_LEVEL)1203*3088717bSVictor Perevertkin _IRQL_requires_max_(APC_LEVEL)
1204*3088717bSVictor Perevertkin VOID DeviceScanForSpecial(
1205*3088717bSVictor Perevertkin     _In_ PCDROM_DEVICE_EXTENSION          DeviceExtension,
1206*3088717bSVictor Perevertkin     _In_ CDROM_SCAN_FOR_SPECIAL_INFO      DeviceList[],
1207*3088717bSVictor Perevertkin     _In_ PCDROM_SCAN_FOR_SPECIAL_HANDLER  Function)
1208*3088717bSVictor Perevertkin /*++
1209*3088717bSVictor Perevertkin 
1210*3088717bSVictor Perevertkin Routine Description:
1211*3088717bSVictor Perevertkin 
1212*3088717bSVictor Perevertkin     scan the list of devices that should be hacked or not supported.
1213*3088717bSVictor Perevertkin 
1214*3088717bSVictor Perevertkin Arguments:
1215*3088717bSVictor Perevertkin 
1216*3088717bSVictor Perevertkin     DeviceExtension - the device context
1217*3088717bSVictor Perevertkin     DeviceList - the device list
1218*3088717bSVictor Perevertkin     Function - function used to scan from the list.
1219*3088717bSVictor Perevertkin 
1220*3088717bSVictor Perevertkin Return Value:
1221*3088717bSVictor Perevertkin 
1222*3088717bSVictor Perevertkin     none
1223*3088717bSVictor Perevertkin 
1224*3088717bSVictor Perevertkin --*/
1225*3088717bSVictor Perevertkin {
1226*3088717bSVictor Perevertkin     PSTORAGE_DEVICE_DESCRIPTOR  deviceDescriptor;
1227*3088717bSVictor Perevertkin     PUCHAR                      vendorId;
1228*3088717bSVictor Perevertkin     PUCHAR                      productId;
1229*3088717bSVictor Perevertkin     PUCHAR                      productRevision;
1230*3088717bSVictor Perevertkin     UCHAR                       nullString[] = "";
1231*3088717bSVictor Perevertkin 
1232*3088717bSVictor Perevertkin     PAGED_CODE();
1233*3088717bSVictor Perevertkin     NT_ASSERT(DeviceList);
1234*3088717bSVictor Perevertkin     NT_ASSERT(Function);
1235*3088717bSVictor Perevertkin 
1236*3088717bSVictor Perevertkin     if (DeviceList == NULL)
1237*3088717bSVictor Perevertkin     {
1238*3088717bSVictor Perevertkin         return;
1239*3088717bSVictor Perevertkin     }
1240*3088717bSVictor Perevertkin     if (Function == NULL)
1241*3088717bSVictor Perevertkin     {
1242*3088717bSVictor Perevertkin         return;
1243*3088717bSVictor Perevertkin     }
1244*3088717bSVictor Perevertkin 
1245*3088717bSVictor Perevertkin     deviceDescriptor = DeviceExtension->DeviceDescriptor;
1246*3088717bSVictor Perevertkin 
1247*3088717bSVictor Perevertkin     // SCSI sets offsets to -1, ATAPI sets to 0.  check for both.
1248*3088717bSVictor Perevertkin     if (deviceDescriptor->VendorIdOffset != 0 &&
1249*3088717bSVictor Perevertkin         deviceDescriptor->VendorIdOffset != -1)
1250*3088717bSVictor Perevertkin     {
1251*3088717bSVictor Perevertkin         vendorId = ((PUCHAR)deviceDescriptor);
1252*3088717bSVictor Perevertkin         vendorId += deviceDescriptor->VendorIdOffset;
1253*3088717bSVictor Perevertkin     }
1254*3088717bSVictor Perevertkin     else
1255*3088717bSVictor Perevertkin     {
1256*3088717bSVictor Perevertkin         vendorId = nullString;
1257*3088717bSVictor Perevertkin     }
1258*3088717bSVictor Perevertkin 
1259*3088717bSVictor Perevertkin     if (deviceDescriptor->ProductIdOffset != 0 &&
1260*3088717bSVictor Perevertkin         deviceDescriptor->ProductIdOffset != -1)
1261*3088717bSVictor Perevertkin     {
1262*3088717bSVictor Perevertkin         productId = ((PUCHAR)deviceDescriptor);
1263*3088717bSVictor Perevertkin         productId += deviceDescriptor->ProductIdOffset;
1264*3088717bSVictor Perevertkin     }
1265*3088717bSVictor Perevertkin     else
1266*3088717bSVictor Perevertkin     {
1267*3088717bSVictor Perevertkin         productId = nullString;
1268*3088717bSVictor Perevertkin     }
1269*3088717bSVictor Perevertkin 
1270*3088717bSVictor Perevertkin     if (deviceDescriptor->ProductRevisionOffset != 0 &&
1271*3088717bSVictor Perevertkin         deviceDescriptor->ProductRevisionOffset != -1)
1272*3088717bSVictor Perevertkin     {
1273*3088717bSVictor Perevertkin         productRevision = ((PUCHAR)deviceDescriptor);
1274*3088717bSVictor Perevertkin         productRevision += deviceDescriptor->ProductRevisionOffset;
1275*3088717bSVictor Perevertkin     }
1276*3088717bSVictor Perevertkin     else
1277*3088717bSVictor Perevertkin     {
1278*3088717bSVictor Perevertkin         productRevision = nullString;
1279*3088717bSVictor Perevertkin     }
1280*3088717bSVictor Perevertkin 
1281*3088717bSVictor Perevertkin     // loop while the device list is valid (not null-filled)
1282*3088717bSVictor Perevertkin     for (;(DeviceList->VendorId        != NULL ||
1283*3088717bSVictor Perevertkin            DeviceList->ProductId       != NULL ||
1284*3088717bSVictor Perevertkin            DeviceList->ProductRevision != NULL); DeviceList++)
1285*3088717bSVictor Perevertkin     {
1286*3088717bSVictor Perevertkin         if (StringsAreMatched(DeviceList->VendorId,        (LPSTR)vendorId) &&
1287*3088717bSVictor Perevertkin             StringsAreMatched(DeviceList->ProductId,       (LPSTR)productId) &&
1288*3088717bSVictor Perevertkin             StringsAreMatched(DeviceList->ProductRevision, (LPSTR)productRevision)
1289*3088717bSVictor Perevertkin             )
1290*3088717bSVictor Perevertkin         {
1291*3088717bSVictor Perevertkin 
1292*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, "DeviceScanForSpecial: Found matching "
1293*3088717bSVictor Perevertkin                         "controller Ven: %s Prod: %s Rev: %s\n",
1294*3088717bSVictor Perevertkin                         (LPCSTR)vendorId, (LPCSTR)productId, (LPCSTR)productRevision));
1295*3088717bSVictor Perevertkin 
1296*3088717bSVictor Perevertkin             // pass the context to the call back routine and exit
1297*3088717bSVictor Perevertkin             (Function)(DeviceExtension, DeviceList->Data);
1298*3088717bSVictor Perevertkin 
1299*3088717bSVictor Perevertkin             // for CHK builds, try to prevent wierd stacks by having a debug
1300*3088717bSVictor Perevertkin             // print here. it's a hack, but i know of no other way to prevent
1301*3088717bSVictor Perevertkin             // the stack from being wrong.
1302*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, "DeviceScanForSpecial: "
1303*3088717bSVictor Perevertkin                         "completed callback\n"));
1304*3088717bSVictor Perevertkin             return;
1305*3088717bSVictor Perevertkin 
1306*3088717bSVictor Perevertkin         } // else the strings did not match
1307*3088717bSVictor Perevertkin 
1308*3088717bSVictor Perevertkin     } // none of the devices matched.
1309*3088717bSVictor Perevertkin 
1310*3088717bSVictor Perevertkin     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, "DeviceScanForSpecial: no match found for %p\n",
1311*3088717bSVictor Perevertkin                 DeviceExtension->DeviceObject));
1312*3088717bSVictor Perevertkin     return;
1313*3088717bSVictor Perevertkin 
1314*3088717bSVictor Perevertkin } // end DeviceScanForSpecial()
1315*3088717bSVictor Perevertkin 
_IRQL_requires_max_(APC_LEVEL)1316*3088717bSVictor Perevertkin _IRQL_requires_max_(APC_LEVEL)
1317*3088717bSVictor Perevertkin VOID
1318*3088717bSVictor Perevertkin DeviceHackFlagsScan(
1319*3088717bSVictor Perevertkin     _In_ PCDROM_DEVICE_EXTENSION  DeviceExtension,
1320*3088717bSVictor Perevertkin     _In_ ULONG_PTR                Data
1321*3088717bSVictor Perevertkin     )
1322*3088717bSVictor Perevertkin {
1323*3088717bSVictor Perevertkin     PAGED_CODE();
1324*3088717bSVictor Perevertkin 
1325*3088717bSVictor Perevertkin     // remove invalid flags and save
1326*3088717bSVictor Perevertkin     CLEAR_FLAG(Data, FDO_HACK_INVALID_FLAGS);
1327*3088717bSVictor Perevertkin     SET_FLAG(DeviceExtension->PrivateFdoData->HackFlags, Data);
1328*3088717bSVictor Perevertkin 
1329*3088717bSVictor Perevertkin     return;
1330*3088717bSVictor Perevertkin }
1331*3088717bSVictor Perevertkin 
1332*3088717bSVictor Perevertkin 
_IRQL_requires_max_(PASSIVE_LEVEL)1333*3088717bSVictor Perevertkin _IRQL_requires_max_(PASSIVE_LEVEL)
1334*3088717bSVictor Perevertkin NTSTATUS
1335*3088717bSVictor Perevertkin DeviceInitializeHotplugInfo(
1336*3088717bSVictor Perevertkin     _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
1337*3088717bSVictor Perevertkin     )
1338*3088717bSVictor Perevertkin /*++
1339*3088717bSVictor Perevertkin 
1340*3088717bSVictor Perevertkin Routine Description:
1341*3088717bSVictor Perevertkin 
1342*3088717bSVictor Perevertkin     Retrieve information into struc STORAGE_HOTPLUG_INFO in DeviceExtension
1343*3088717bSVictor Perevertkin     initialize the hotplug information only after the ScanForSpecial routines,
1344*3088717bSVictor Perevertkin     as it relies upon the hack flags - DeviceExtension->PrivateFdoData->HackFlags.
1345*3088717bSVictor Perevertkin 
1346*3088717bSVictor Perevertkin Arguments:
1347*3088717bSVictor Perevertkin 
1348*3088717bSVictor Perevertkin     DeviceExtension - the device context
1349*3088717bSVictor Perevertkin 
1350*3088717bSVictor Perevertkin Return Value:
1351*3088717bSVictor Perevertkin 
1352*3088717bSVictor Perevertkin     NTSTATUS
1353*3088717bSVictor Perevertkin 
1354*3088717bSVictor Perevertkin --*/
1355*3088717bSVictor Perevertkin {
1356*3088717bSVictor Perevertkin     NTSTATUS                status = STATUS_SUCCESS;
1357*3088717bSVictor Perevertkin     PCDROM_PRIVATE_FDO_DATA fdoData = DeviceExtension->PrivateFdoData;
1358*3088717bSVictor Perevertkin     DEVICE_REMOVAL_POLICY   deviceRemovalPolicy = 0;
1359*3088717bSVictor Perevertkin     ULONG                   resultLength = 0;
1360*3088717bSVictor Perevertkin     ULONG                   writeCacheOverride;
1361*3088717bSVictor Perevertkin 
1362*3088717bSVictor Perevertkin     PAGED_CODE();
1363*3088717bSVictor Perevertkin 
1364*3088717bSVictor Perevertkin     // start with some default settings
1365*3088717bSVictor Perevertkin     RtlZeroMemory(&(fdoData->HotplugInfo), sizeof(STORAGE_HOTPLUG_INFO));
1366*3088717bSVictor Perevertkin 
1367*3088717bSVictor Perevertkin     // set the size (aka version)
1368*3088717bSVictor Perevertkin     fdoData->HotplugInfo.Size = sizeof(STORAGE_HOTPLUG_INFO);
1369*3088717bSVictor Perevertkin 
1370*3088717bSVictor Perevertkin     // set if the device has removable media
1371*3088717bSVictor Perevertkin     if (DeviceExtension->DeviceDescriptor->RemovableMedia)
1372*3088717bSVictor Perevertkin     {
1373*3088717bSVictor Perevertkin         fdoData->HotplugInfo.MediaRemovable = TRUE;
1374*3088717bSVictor Perevertkin     }
1375*3088717bSVictor Perevertkin     else
1376*3088717bSVictor Perevertkin     {
1377*3088717bSVictor Perevertkin         fdoData->HotplugInfo.MediaRemovable = FALSE;
1378*3088717bSVictor Perevertkin     }
1379*3088717bSVictor Perevertkin 
1380*3088717bSVictor Perevertkin     //
1381*3088717bSVictor Perevertkin     // this refers to devices which, for reasons not yet understood,
1382*3088717bSVictor Perevertkin     // do not fail PREVENT_MEDIA_REMOVAL requests even though they
1383*3088717bSVictor Perevertkin     // have no way to lock the media into the drive.  this allows
1384*3088717bSVictor Perevertkin     // the filesystems to turn off delayed-write caching for these
1385*3088717bSVictor Perevertkin     // devices as well.
1386*3088717bSVictor Perevertkin     //
1387*3088717bSVictor Perevertkin 
1388*3088717bSVictor Perevertkin     if (TEST_FLAG(DeviceExtension->PrivateFdoData->HackFlags, FDO_HACK_CANNOT_LOCK_MEDIA))
1389*3088717bSVictor Perevertkin     {
1390*3088717bSVictor Perevertkin         fdoData->HotplugInfo.MediaHotplug = TRUE;
1391*3088717bSVictor Perevertkin     }
1392*3088717bSVictor Perevertkin     else
1393*3088717bSVictor Perevertkin     {
1394*3088717bSVictor Perevertkin         fdoData->HotplugInfo.MediaHotplug = FALSE;
1395*3088717bSVictor Perevertkin     }
1396*3088717bSVictor Perevertkin 
1397*3088717bSVictor Perevertkin     // Query the default removal policy from the kernel
1398*3088717bSVictor Perevertkin     status = WdfDeviceQueryProperty(DeviceExtension->Device,
1399*3088717bSVictor Perevertkin                                     DevicePropertyRemovalPolicy,
1400*3088717bSVictor Perevertkin                                     sizeof(DEVICE_REMOVAL_POLICY),
1401*3088717bSVictor Perevertkin                                     (PVOID)&deviceRemovalPolicy,
1402*3088717bSVictor Perevertkin                                     &resultLength);
1403*3088717bSVictor Perevertkin     if (NT_SUCCESS(status))
1404*3088717bSVictor Perevertkin     {
1405*3088717bSVictor Perevertkin         if (resultLength != sizeof(DEVICE_REMOVAL_POLICY))
1406*3088717bSVictor Perevertkin         {
1407*3088717bSVictor Perevertkin             status = STATUS_UNSUCCESSFUL;
1408*3088717bSVictor Perevertkin         }
1409*3088717bSVictor Perevertkin     }
1410*3088717bSVictor Perevertkin 
1411*3088717bSVictor Perevertkin     if (NT_SUCCESS(status))
1412*3088717bSVictor Perevertkin     {
1413*3088717bSVictor Perevertkin         // Look into the registry to see if the user has chosen
1414*3088717bSVictor Perevertkin         // to override the default setting for the removal policy.
1415*3088717bSVictor Perevertkin         // User can override only if the default removal policy is
1416*3088717bSVictor Perevertkin         // orderly or suprise removal.
1417*3088717bSVictor Perevertkin 
1418*3088717bSVictor Perevertkin         if ((deviceRemovalPolicy == RemovalPolicyExpectOrderlyRemoval) ||
1419*3088717bSVictor Perevertkin             (deviceRemovalPolicy == RemovalPolicyExpectSurpriseRemoval))
1420*3088717bSVictor Perevertkin         {
1421*3088717bSVictor Perevertkin             DEVICE_REMOVAL_POLICY userRemovalPolicy = 0;
1422*3088717bSVictor Perevertkin 
1423*3088717bSVictor Perevertkin             DeviceGetParameter(DeviceExtension,
1424*3088717bSVictor Perevertkin                                 CLASSP_REG_SUBKEY_NAME,
1425*3088717bSVictor Perevertkin                                 CLASSP_REG_REMOVAL_POLICY_VALUE_NAME,
1426*3088717bSVictor Perevertkin                                 (PULONG)&userRemovalPolicy);
1427*3088717bSVictor Perevertkin 
1428*3088717bSVictor Perevertkin             // Validate the override value and use it only if it is an
1429*3088717bSVictor Perevertkin             // allowed value.
1430*3088717bSVictor Perevertkin             if ((userRemovalPolicy == RemovalPolicyExpectOrderlyRemoval) ||
1431*3088717bSVictor Perevertkin                 (userRemovalPolicy == RemovalPolicyExpectSurpriseRemoval))
1432*3088717bSVictor Perevertkin             {
1433*3088717bSVictor Perevertkin                 deviceRemovalPolicy = userRemovalPolicy;
1434*3088717bSVictor Perevertkin             }
1435*3088717bSVictor Perevertkin         }
1436*3088717bSVictor Perevertkin 
1437*3088717bSVictor Perevertkin         // use this info to set the DeviceHotplug setting
1438*3088717bSVictor Perevertkin         // don't rely on DeviceCapabilities, since it can't properly
1439*3088717bSVictor Perevertkin         // determine device relations, etc.  let the kernel figure this
1440*3088717bSVictor Perevertkin         // stuff out instead.
1441*3088717bSVictor Perevertkin         if (deviceRemovalPolicy == RemovalPolicyExpectSurpriseRemoval)
1442*3088717bSVictor Perevertkin         {
1443*3088717bSVictor Perevertkin             fdoData->HotplugInfo.DeviceHotplug = TRUE;
1444*3088717bSVictor Perevertkin         }
1445*3088717bSVictor Perevertkin         else
1446*3088717bSVictor Perevertkin         {
1447*3088717bSVictor Perevertkin             fdoData->HotplugInfo.DeviceHotplug = FALSE;
1448*3088717bSVictor Perevertkin         }
1449*3088717bSVictor Perevertkin 
1450*3088717bSVictor Perevertkin         // this refers to the *filesystem* caching, but has to be included
1451*3088717bSVictor Perevertkin         // here since it's a per-device setting.  this may change to be
1452*3088717bSVictor Perevertkin         // stored by the system in the future.
1453*3088717bSVictor Perevertkin         writeCacheOverride = FALSE;
1454*3088717bSVictor Perevertkin         DeviceGetParameter(DeviceExtension,
1455*3088717bSVictor Perevertkin                             CLASSP_REG_SUBKEY_NAME,
1456*3088717bSVictor Perevertkin                             CLASSP_REG_WRITE_CACHE_VALUE_NAME,
1457*3088717bSVictor Perevertkin                             &writeCacheOverride);
1458*3088717bSVictor Perevertkin 
1459*3088717bSVictor Perevertkin         if (writeCacheOverride)
1460*3088717bSVictor Perevertkin         {
1461*3088717bSVictor Perevertkin             fdoData->HotplugInfo.WriteCacheEnableOverride = TRUE;
1462*3088717bSVictor Perevertkin         }
1463*3088717bSVictor Perevertkin         else
1464*3088717bSVictor Perevertkin         {
1465*3088717bSVictor Perevertkin             fdoData->HotplugInfo.WriteCacheEnableOverride = FALSE;
1466*3088717bSVictor Perevertkin         }
1467*3088717bSVictor Perevertkin     }
1468*3088717bSVictor Perevertkin 
1469*3088717bSVictor Perevertkin     if (!NT_SUCCESS(status))
1470*3088717bSVictor Perevertkin     {
1471*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT,  "Could not initialize hotplug information %lx\n", status));
1472*3088717bSVictor Perevertkin     }
1473*3088717bSVictor Perevertkin 
1474*3088717bSVictor Perevertkin     return status;
1475*3088717bSVictor Perevertkin }
1476*3088717bSVictor Perevertkin 
1477*3088717bSVictor Perevertkin 
_IRQL_requires_max_(PASSIVE_LEVEL)1478*3088717bSVictor Perevertkin _IRQL_requires_max_(PASSIVE_LEVEL)
1479*3088717bSVictor Perevertkin NTSTATUS
1480*3088717bSVictor Perevertkin DeviceInitMmcContext(
1481*3088717bSVictor Perevertkin     _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
1482*3088717bSVictor Perevertkin     )
1483*3088717bSVictor Perevertkin /*++
1484*3088717bSVictor Perevertkin 
1485*3088717bSVictor Perevertkin Routine Description:
1486*3088717bSVictor Perevertkin 
1487*3088717bSVictor Perevertkin     This routine initializes and populates the internal data structures that are
1488*3088717bSVictor Perevertkin     used to discover various MMC-defined capabilities of the device.
1489*3088717bSVictor Perevertkin 
1490*3088717bSVictor Perevertkin     This routine will not clean up allocate resources if it fails - that
1491*3088717bSVictor Perevertkin     is left for device stop/removal routines
1492*3088717bSVictor Perevertkin 
1493*3088717bSVictor Perevertkin Arguments:
1494*3088717bSVictor Perevertkin 
1495*3088717bSVictor Perevertkin     DeviceExtension - device extension
1496*3088717bSVictor Perevertkin 
1497*3088717bSVictor Perevertkin Return Value:
1498*3088717bSVictor Perevertkin 
1499*3088717bSVictor Perevertkin     NTSTATUS
1500*3088717bSVictor Perevertkin 
1501*3088717bSVictor Perevertkin --*/
1502*3088717bSVictor Perevertkin {
1503*3088717bSVictor Perevertkin     NTSTATUS                    status = STATUS_SUCCESS;
1504*3088717bSVictor Perevertkin 
1505*3088717bSVictor Perevertkin     PAGED_CODE();
1506*3088717bSVictor Perevertkin 
1507*3088717bSVictor Perevertkin     DeviceExtension->DeviceAdditionalData.Mmc.IsMmc = FALSE;
1508*3088717bSVictor Perevertkin     DeviceExtension->DeviceAdditionalData.Mmc.IsAACS = FALSE;
1509*3088717bSVictor Perevertkin     DeviceExtension->DeviceAdditionalData.Mmc.IsWriter = FALSE;
1510*3088717bSVictor Perevertkin     DeviceExtension->DeviceAdditionalData.Mmc.WriteAllowed = FALSE;
1511*3088717bSVictor Perevertkin     DeviceExtension->DeviceAdditionalData.Mmc.IsCssDvd = FALSE;
1512*3088717bSVictor Perevertkin     DeviceExtension->DeviceAdditionalData.DriveDeviceType = FILE_DEVICE_CD_ROM;
1513*3088717bSVictor Perevertkin 
1514*3088717bSVictor Perevertkin     // Determine if the drive is MMC-Capable
1515*3088717bSVictor Perevertkin     if (NT_SUCCESS(status))
1516*3088717bSVictor Perevertkin     {
1517*3088717bSVictor Perevertkin         status = DeviceGetMmcSupportInfo(DeviceExtension,
1518*3088717bSVictor Perevertkin                                          &DeviceExtension->DeviceAdditionalData.Mmc.IsMmc);
1519*3088717bSVictor Perevertkin 
1520*3088717bSVictor Perevertkin         if (!NT_SUCCESS(status))
1521*3088717bSVictor Perevertkin         {
1522*3088717bSVictor Perevertkin             //Currently, only low resource error comes here.
1523*3088717bSVictor Perevertkin             //That is a success case for unsupporting this command.
1524*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT,
1525*3088717bSVictor Perevertkin                         "DeviceInitMmcContext: Failed to get the support info for GET CONFIGURATION "
1526*3088717bSVictor Perevertkin                         "command, failng %!STATUS!\n", status
1527*3088717bSVictor Perevertkin                         ));
1528*3088717bSVictor Perevertkin 
1529*3088717bSVictor Perevertkin             DeviceExtension->DeviceAdditionalData.Mmc.IsMmc = FALSE;
1530*3088717bSVictor Perevertkin             status = STATUS_SUCCESS;
1531*3088717bSVictor Perevertkin         }
1532*3088717bSVictor Perevertkin     }
1533*3088717bSVictor Perevertkin 
1534*3088717bSVictor Perevertkin     if (NT_SUCCESS(status) && DeviceExtension->DeviceAdditionalData.Mmc.IsMmc)
1535*3088717bSVictor Perevertkin     {
1536*3088717bSVictor Perevertkin         // the drive supports at least a subset of MMC commands
1537*3088717bSVictor Perevertkin         // (and therefore supports READ_CD, etc...)
1538*3088717bSVictor Perevertkin 
1539*3088717bSVictor Perevertkin         // allocate a buffer for all the capabilities and such
1540*3088717bSVictor Perevertkin         status = DeviceAllocateMmcResources(DeviceExtension->Device);
1541*3088717bSVictor Perevertkin     }
1542*3088717bSVictor Perevertkin 
1543*3088717bSVictor Perevertkin     if (NT_SUCCESS(status) && DeviceExtension->DeviceAdditionalData.Mmc.IsMmc)
1544*3088717bSVictor Perevertkin     {
1545*3088717bSVictor Perevertkin         PFEATURE_HEADER header = NULL;
1546*3088717bSVictor Perevertkin         FEATURE_NUMBER  validationSchema;
1547*3088717bSVictor Perevertkin         ULONG           blockingFactor;
1548*3088717bSVictor Perevertkin 
1549*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
1550*3088717bSVictor Perevertkin                   "DeviceInitMmcContext: FDO %p GET CONFIGURATION buffer %p\n",
1551*3088717bSVictor Perevertkin                   DeviceExtension->Device,
1552*3088717bSVictor Perevertkin                   DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBuffer
1553*3088717bSVictor Perevertkin                   ));
1554*3088717bSVictor Perevertkin 
1555*3088717bSVictor Perevertkin         // Update several properties using the retrieved Configuration Data.
1556*3088717bSVictor Perevertkin 
1557*3088717bSVictor Perevertkin         // print all the feature pages (DBG only)
1558*3088717bSVictor Perevertkin         DevicePrintAllFeaturePages(DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBuffer,
1559*3088717bSVictor Perevertkin                                    DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBufferSize);
1560*3088717bSVictor Perevertkin 
1561*3088717bSVictor Perevertkin         // if AACS feature exists, enable AACS flag in the driver
1562*3088717bSVictor Perevertkin         header = DeviceFindFeaturePage(DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBuffer,
1563*3088717bSVictor Perevertkin                                        DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBufferSize,
1564*3088717bSVictor Perevertkin                                        FeatureAACS);
1565*3088717bSVictor Perevertkin         if (header)
1566*3088717bSVictor Perevertkin         {
1567*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
1568*3088717bSVictor Perevertkin                         "DeviceInitMmcContext: Reporting AACS support for device due to "
1569*3088717bSVictor Perevertkin                         "GET CONFIGURATION showing support\n"
1570*3088717bSVictor Perevertkin                         ));
1571*3088717bSVictor Perevertkin             DeviceExtension->DeviceAdditionalData.Mmc.IsAACS = TRUE;
1572*3088717bSVictor Perevertkin         }
1573*3088717bSVictor Perevertkin 
1574*3088717bSVictor Perevertkin #ifdef ENABLE_AACS_TESTING
1575*3088717bSVictor Perevertkin         DeviceExtension->DeviceAdditionalData.Mmc.IsAACS = TRUE; // just force it true for testing
1576*3088717bSVictor Perevertkin #endif // ENABLE_AACS_TESTING
1577*3088717bSVictor Perevertkin 
1578*3088717bSVictor Perevertkin         // Check if it's a DVD device
1579*3088717bSVictor Perevertkin         header = DeviceFindFeaturePage(DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBuffer,
1580*3088717bSVictor Perevertkin                                        DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBufferSize,
1581*3088717bSVictor Perevertkin                                        FeatureDvdRead);
1582*3088717bSVictor Perevertkin         if (header != NULL)
1583*3088717bSVictor Perevertkin         {
1584*3088717bSVictor Perevertkin             DeviceExtension->DeviceAdditionalData.DriveDeviceType = FILE_DEVICE_DVD;
1585*3088717bSVictor Perevertkin         }
1586*3088717bSVictor Perevertkin 
1587*3088717bSVictor Perevertkin         // check if drive is writer
1588*3088717bSVictor Perevertkin         DeviceUpdateMmcWriteCapability(DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBuffer,
1589*3088717bSVictor Perevertkin                                        DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBufferSize,
1590*3088717bSVictor Perevertkin                                        FALSE,                //Check if the drive has the ability to write.
1591*3088717bSVictor Perevertkin                                        (PBOOLEAN)&(DeviceExtension->DeviceAdditionalData.Mmc.IsWriter),
1592*3088717bSVictor Perevertkin                                        &validationSchema,
1593*3088717bSVictor Perevertkin                                        &blockingFactor);
1594*3088717bSVictor Perevertkin 
1595*3088717bSVictor Perevertkin         // check if there is a CSS protected DVD or CPPM-protected DVDAudio media in drive.
1596*3088717bSVictor Perevertkin         header = DeviceFindFeaturePage(DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBuffer,
1597*3088717bSVictor Perevertkin                                        DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBufferSize,
1598*3088717bSVictor Perevertkin                                        FeatureDvdCSS);
1599*3088717bSVictor Perevertkin 
1600*3088717bSVictor Perevertkin         DeviceExtension->DeviceAdditionalData.Mmc.IsCssDvd = (header != NULL) && (header->Current);
1601*3088717bSVictor Perevertkin 
1602*3088717bSVictor Perevertkin         // Flag the StartIo routine to update its state and hook in the error handler
1603*3088717bSVictor Perevertkin         DeviceExtension->DeviceAdditionalData.Mmc.UpdateState = CdromMmcUpdateRequired;
1604*3088717bSVictor Perevertkin         DeviceExtension->DeviceAdditionalData.ErrorHandler = DeviceErrorHandlerForMmc;
1605*3088717bSVictor Perevertkin 
1606*3088717bSVictor Perevertkin         SET_FLAG(DeviceExtension->DeviceFlags, DEV_SAFE_START_UNIT);
1607*3088717bSVictor Perevertkin 
1608*3088717bSVictor Perevertkin         // Read the CDROM mode sense page to get additional info for raw read requests.
1609*3088717bSVictor Perevertkin         // only valid for MMC devices
1610*3088717bSVictor Perevertkin         DeviceSetRawReadInfo(DeviceExtension);
1611*3088717bSVictor Perevertkin     }
1612*3088717bSVictor Perevertkin 
1613*3088717bSVictor Perevertkin     // Set Read-Only device flag for non-MMC device.
1614*3088717bSVictor Perevertkin     if (!(DeviceExtension->DeviceAdditionalData.Mmc.IsMmc))
1615*3088717bSVictor Perevertkin     {
1616*3088717bSVictor Perevertkin         ULONG  deviceCharacteristics = WdfDeviceGetCharacteristics(DeviceExtension->Device);
1617*3088717bSVictor Perevertkin 
1618*3088717bSVictor Perevertkin         deviceCharacteristics |= FILE_READ_ONLY_DEVICE;
1619*3088717bSVictor Perevertkin 
1620*3088717bSVictor Perevertkin         WdfDeviceSetCharacteristics(DeviceExtension->Device, deviceCharacteristics);
1621*3088717bSVictor Perevertkin 
1622*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
1623*3088717bSVictor Perevertkin                    "DeviceInitMmcContext: FDO %p Device is not an MMC compliant device, so setting "
1624*3088717bSVictor Perevertkin                    "to read-only (legacy) mode",
1625*3088717bSVictor Perevertkin                    DeviceExtension->Device
1626*3088717bSVictor Perevertkin                    ));
1627*3088717bSVictor Perevertkin     }
1628*3088717bSVictor Perevertkin 
1629*3088717bSVictor Perevertkin     // Set DEV_SAFE_START_UNIT flag for newer devices.
1630*3088717bSVictor Perevertkin     if (DeviceExtension->DeviceAdditionalData.DriveDeviceType == FILE_DEVICE_DVD)
1631*3088717bSVictor Perevertkin     {
1632*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
1633*3088717bSVictor Perevertkin                     "DeviceInitMmcContext: DVD Devices require START UNIT\n"));
1634*3088717bSVictor Perevertkin         SET_FLAG(DeviceExtension->DeviceFlags, DEV_SAFE_START_UNIT);
1635*3088717bSVictor Perevertkin 
1636*3088717bSVictor Perevertkin     }
1637*3088717bSVictor Perevertkin     else if ((DeviceExtension->DeviceDescriptor->BusType != BusTypeScsi)  &&
1638*3088717bSVictor Perevertkin              (DeviceExtension->DeviceDescriptor->BusType != BusTypeAtapi) &&
1639*3088717bSVictor Perevertkin              (DeviceExtension->DeviceDescriptor->BusType != BusTypeUnknown)
1640*3088717bSVictor Perevertkin              )
1641*3088717bSVictor Perevertkin     {
1642*3088717bSVictor Perevertkin         // devices on the newer busses require START_UNIT
1643*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
1644*3088717bSVictor Perevertkin                   "DeviceInitMmcContext: Devices for newer buses require START UNIT\n"));
1645*3088717bSVictor Perevertkin         SET_FLAG(DeviceExtension->DeviceFlags, DEV_SAFE_START_UNIT);
1646*3088717bSVictor Perevertkin     }
1647*3088717bSVictor Perevertkin 
1648*3088717bSVictor Perevertkin     return status;
1649*3088717bSVictor Perevertkin }
1650*3088717bSVictor Perevertkin 
1651*3088717bSVictor Perevertkin 
_IRQL_requires_max_(PASSIVE_LEVEL)1652*3088717bSVictor Perevertkin _IRQL_requires_max_(PASSIVE_LEVEL)
1653*3088717bSVictor Perevertkin ULONG
1654*3088717bSVictor Perevertkin DeviceGetTimeOutValueFromRegistry()
1655*3088717bSVictor Perevertkin /*++
1656*3088717bSVictor Perevertkin 
1657*3088717bSVictor Perevertkin Routine Description:
1658*3088717bSVictor Perevertkin 
1659*3088717bSVictor Perevertkin     get the device time out value from registry
1660*3088717bSVictor Perevertkin 
1661*3088717bSVictor Perevertkin Arguments:
1662*3088717bSVictor Perevertkin 
1663*3088717bSVictor Perevertkin     None
1664*3088717bSVictor Perevertkin 
1665*3088717bSVictor Perevertkin Return Value:
1666*3088717bSVictor Perevertkin 
1667*3088717bSVictor Perevertkin     ULONG - value of timeout
1668*3088717bSVictor Perevertkin 
1669*3088717bSVictor Perevertkin --*/
1670*3088717bSVictor Perevertkin {
1671*3088717bSVictor Perevertkin     NTSTATUS    status;
1672*3088717bSVictor Perevertkin     WDFKEY      registryKey = NULL;
1673*3088717bSVictor Perevertkin     ULONG        timeOutValue = 0;
1674*3088717bSVictor Perevertkin 
1675*3088717bSVictor Perevertkin     DECLARE_CONST_UNICODE_STRING(registryValueName, L"TimeOutValue");
1676*3088717bSVictor Perevertkin 
1677*3088717bSVictor Perevertkin     PAGED_CODE();
1678*3088717bSVictor Perevertkin 
1679*3088717bSVictor Perevertkin     // open the service key.
1680*3088717bSVictor Perevertkin     status = WdfDriverOpenParametersRegistryKey(WdfGetDriver(),
1681*3088717bSVictor Perevertkin                                                 KEY_READ,
1682*3088717bSVictor Perevertkin                                                 WDF_NO_OBJECT_ATTRIBUTES,
1683*3088717bSVictor Perevertkin                                                 &registryKey);
1684*3088717bSVictor Perevertkin 
1685*3088717bSVictor Perevertkin     if (NT_SUCCESS(status))
1686*3088717bSVictor Perevertkin     {
1687*3088717bSVictor Perevertkin         status = WdfRegistryQueryULong(registryKey,
1688*3088717bSVictor Perevertkin                                        &registryValueName,
1689*3088717bSVictor Perevertkin                                        &timeOutValue);
1690*3088717bSVictor Perevertkin 
1691*3088717bSVictor Perevertkin         WdfRegistryClose(registryKey);
1692*3088717bSVictor Perevertkin     }
1693*3088717bSVictor Perevertkin 
1694*3088717bSVictor Perevertkin     if (!NT_SUCCESS(status))
1695*3088717bSVictor Perevertkin     {
1696*3088717bSVictor Perevertkin         timeOutValue = 0;
1697*3088717bSVictor Perevertkin     }
1698*3088717bSVictor Perevertkin 
1699*3088717bSVictor Perevertkin     return timeOutValue;
1700*3088717bSVictor Perevertkin 
1701*3088717bSVictor Perevertkin } // end DeviceGetTimeOutValueFromRegistry()
1702*3088717bSVictor Perevertkin 
1703*3088717bSVictor Perevertkin 
_IRQL_requires_max_(APC_LEVEL)1704*3088717bSVictor Perevertkin _IRQL_requires_max_(APC_LEVEL)
1705*3088717bSVictor Perevertkin VOID
1706*3088717bSVictor Perevertkin DeviceScanSpecialDevices(
1707*3088717bSVictor Perevertkin     _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
1708*3088717bSVictor Perevertkin     )
1709*3088717bSVictor Perevertkin /*++
1710*3088717bSVictor Perevertkin 
1711*3088717bSVictor Perevertkin Routine Description:
1712*3088717bSVictor Perevertkin 
1713*3088717bSVictor Perevertkin     This function checks to see if an SCSI logical unit requires an special
1714*3088717bSVictor Perevertkin     initialization or error processing.
1715*3088717bSVictor Perevertkin 
1716*3088717bSVictor Perevertkin Arguments:
1717*3088717bSVictor Perevertkin 
1718*3088717bSVictor Perevertkin     Device - device object.
1719*3088717bSVictor Perevertkin 
1720*3088717bSVictor Perevertkin Return Value:
1721*3088717bSVictor Perevertkin 
1722*3088717bSVictor Perevertkin     None.
1723*3088717bSVictor Perevertkin 
1724*3088717bSVictor Perevertkin --*/
1725*3088717bSVictor Perevertkin {
1726*3088717bSVictor Perevertkin 
1727*3088717bSVictor Perevertkin     PAGED_CODE();
1728*3088717bSVictor Perevertkin 
1729*3088717bSVictor Perevertkin     // set our hack flags
1730*3088717bSVictor Perevertkin     DeviceScanForSpecial(DeviceExtension, CdromHackItems, ScanForSpecialHandler);
1731*3088717bSVictor Perevertkin 
1732*3088717bSVictor Perevertkin     //
1733*3088717bSVictor Perevertkin     // All CDRom's can ignore the queue lock failure for power operations
1734*3088717bSVictor Perevertkin     // and do not require handling the SpinUp case (unknown result of sending
1735*3088717bSVictor Perevertkin     // a cdrom a START_UNIT command -- may eject disks?)
1736*3088717bSVictor Perevertkin     //
1737*3088717bSVictor Perevertkin     // We send the stop command mostly to stop outstanding asynch operations
1738*3088717bSVictor Perevertkin     // (like audio playback) from running when the system is powered off.
1739*3088717bSVictor Perevertkin     // Because of this and the unlikely chance that a PLAY command will be
1740*3088717bSVictor Perevertkin     // sent in the window between the STOP and the time the machine powers down
1741*3088717bSVictor Perevertkin     // we don't require queue locks.  This is important because without them
1742*3088717bSVictor Perevertkin     // classpnp's power routines will send the START_STOP_UNIT command to the
1743*3088717bSVictor Perevertkin     // device whether or not it supports locking (atapi does not support locking
1744*3088717bSVictor Perevertkin     // and if we requested them we would end up not stopping audio on atapi
1745*3088717bSVictor Perevertkin     // devices).
1746*3088717bSVictor Perevertkin //    SET_FLAG(deviceExtension->ScanForSpecialFlags, CDROM_SPECIAL_DISABLE_SPIN_UP);
1747*3088717bSVictor Perevertkin //    SET_FLAG(deviceExtension->ScanForSpecialFlags, CDROM_SPECIAL_NO_QUEUE_LOCK);
1748*3088717bSVictor Perevertkin 
1749*3088717bSVictor Perevertkin     if (TEST_FLAG(DeviceExtension->DeviceAdditionalData.HackFlags, CDROM_HACK_TOSHIBA_SD_W1101))
1750*3088717bSVictor Perevertkin     {
1751*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
1752*3088717bSVictor Perevertkin                     "DeviceScanSpecialDevices: Found Toshiba SD-W1101 DVD-RAM "
1753*3088717bSVictor Perevertkin                     "-- This drive will *NOT* support DVD-ROM playback.\n"));
1754*3088717bSVictor Perevertkin     }
1755*3088717bSVictor Perevertkin     else if (TEST_FLAG(DeviceExtension->DeviceAdditionalData.HackFlags, CDROM_HACK_HITACHI_GD_2000))
1756*3088717bSVictor Perevertkin     {
1757*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
1758*3088717bSVictor Perevertkin                     "DeviceScanSpecialDevices: Found Hitachi GD-2000\n"));
1759*3088717bSVictor Perevertkin 
1760*3088717bSVictor Perevertkin         // Setup an error handler to spin up the drive when it idles out
1761*3088717bSVictor Perevertkin         // since it seems to like to fail to spin itself back up on its
1762*3088717bSVictor Perevertkin         // own for a REPORT_KEY command.  It may also lose the AGIDs that
1763*3088717bSVictor Perevertkin         // it has given, which will result in DVD playback failures.
1764*3088717bSVictor Perevertkin         // This routine will just do what it can...
1765*3088717bSVictor Perevertkin         DeviceExtension->DeviceAdditionalData.ErrorHandler = DeviceErrorHandlerForHitachiGD2000;
1766*3088717bSVictor Perevertkin 
1767*3088717bSVictor Perevertkin         // this drive may require START_UNIT commands to spin
1768*3088717bSVictor Perevertkin         // the drive up when it's spun itself down.
1769*3088717bSVictor Perevertkin         SET_FLAG(DeviceExtension->DeviceFlags, DEV_SAFE_START_UNIT);
1770*3088717bSVictor Perevertkin     }
1771*3088717bSVictor Perevertkin     else if (TEST_FLAG(DeviceExtension->DeviceAdditionalData.HackFlags, CDROM_HACK_FUJITSU_FMCD_10x))
1772*3088717bSVictor Perevertkin     {
1773*3088717bSVictor Perevertkin         // When Read command is issued to FMCD-101 or FMCD-102 and there is a music
1774*3088717bSVictor Perevertkin         // cd in it. It takes longer time than SCSI_CDROM_TIMEOUT before returning
1775*3088717bSVictor Perevertkin         // error status.
1776*3088717bSVictor Perevertkin         DeviceExtension->TimeOutValue = 20;
1777*3088717bSVictor Perevertkin     }
1778*3088717bSVictor Perevertkin     else if (TEST_FLAG(DeviceExtension->DeviceAdditionalData.HackFlags, CDROM_HACK_DEC_RRD))
1779*3088717bSVictor Perevertkin     {
1780*3088717bSVictor Perevertkin         NTSTATUS                   status;
1781*3088717bSVictor Perevertkin         PMODE_PARM_READ_WRITE_DATA modeParameters;
1782*3088717bSVictor Perevertkin         SCSI_REQUEST_BLOCK         srb = {0};
1783*3088717bSVictor Perevertkin         PCDB                       cdb;
1784*3088717bSVictor Perevertkin 
1785*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
1786*3088717bSVictor Perevertkin                     "DeviceScanSpecialDevices:  Found DEC RRD.\n"));
1787*3088717bSVictor Perevertkin 
1788*3088717bSVictor Perevertkin         DeviceExtension->DeviceAdditionalData.IsDecRrd = TRUE;
1789*3088717bSVictor Perevertkin 
1790*3088717bSVictor Perevertkin         // Setup an error handler to reinitialize the cd rom after it is reset?
1791*3088717bSVictor Perevertkin         //
1792*3088717bSVictor Perevertkin         //DeviceExtension->DevInfo->ClassError = DecRrdProcessError;
1793*3088717bSVictor Perevertkin 
1794*3088717bSVictor Perevertkin         // Found a DEC RRD cd-rom.  These devices do not pass MS HCT
1795*3088717bSVictor Perevertkin         // multi-media tests because the DEC firmware modifieds the block
1796*3088717bSVictor Perevertkin         // from the PC-standard 2K to 512.  Change the block transfer size
1797*3088717bSVictor Perevertkin         // back to the PC-standard 2K by using a mode select command.
1798*3088717bSVictor Perevertkin 
1799*3088717bSVictor Perevertkin         modeParameters = ExAllocatePoolWithTag(NonPagedPoolNx,
1800*3088717bSVictor Perevertkin                                                sizeof(MODE_PARM_READ_WRITE_DATA),
1801*3088717bSVictor Perevertkin                                                CDROM_TAG_MODE_DATA);
1802*3088717bSVictor Perevertkin         if (modeParameters == NULL)
1803*3088717bSVictor Perevertkin         {
1804*3088717bSVictor Perevertkin             return;
1805*3088717bSVictor Perevertkin         }
1806*3088717bSVictor Perevertkin 
1807*3088717bSVictor Perevertkin         RtlZeroMemory(modeParameters, sizeof(MODE_PARM_READ_WRITE_DATA));
1808*3088717bSVictor Perevertkin         RtlZeroMemory(&srb,           sizeof(SCSI_REQUEST_BLOCK));
1809*3088717bSVictor Perevertkin 
1810*3088717bSVictor Perevertkin         // Set the block length to 2K.
1811*3088717bSVictor Perevertkin         modeParameters->ParameterListHeader.BlockDescriptorLength = sizeof(MODE_PARAMETER_BLOCK);
1812*3088717bSVictor Perevertkin 
1813*3088717bSVictor Perevertkin         // Set block length to 2K (0x0800) in Parameter Block.
1814*3088717bSVictor Perevertkin         modeParameters->ParameterListBlock.BlockLength[0] = 0x00; //MSB
1815*3088717bSVictor Perevertkin         modeParameters->ParameterListBlock.BlockLength[1] = 0x08;
1816*3088717bSVictor Perevertkin         modeParameters->ParameterListBlock.BlockLength[2] = 0x00; //LSB
1817*3088717bSVictor Perevertkin 
1818*3088717bSVictor Perevertkin         // Build the mode select CDB.
1819*3088717bSVictor Perevertkin         srb.CdbLength = 6;
1820*3088717bSVictor Perevertkin         srb.TimeOutValue = DeviceExtension->TimeOutValue;
1821*3088717bSVictor Perevertkin 
1822*3088717bSVictor Perevertkin         cdb = (PCDB)srb.Cdb;
1823*3088717bSVictor Perevertkin         cdb->MODE_SELECT.PFBit               = 1;
1824*3088717bSVictor Perevertkin         cdb->MODE_SELECT.OperationCode       = SCSIOP_MODE_SELECT;
1825*3088717bSVictor Perevertkin         cdb->MODE_SELECT.ParameterListLength = HITACHI_MODE_DATA_SIZE;
1826*3088717bSVictor Perevertkin 
1827*3088717bSVictor Perevertkin         // Send the request to the device.
1828*3088717bSVictor Perevertkin         status = DeviceSendSrbSynchronously(DeviceExtension->Device,
1829*3088717bSVictor Perevertkin                                             &srb,
1830*3088717bSVictor Perevertkin                                             modeParameters,
1831*3088717bSVictor Perevertkin                                             sizeof(MODE_PARM_READ_WRITE_DATA),
1832*3088717bSVictor Perevertkin                                             TRUE,
1833*3088717bSVictor Perevertkin                                             NULL);
1834*3088717bSVictor Perevertkin 
1835*3088717bSVictor Perevertkin         if (!NT_SUCCESS(status))
1836*3088717bSVictor Perevertkin         {
1837*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT,
1838*3088717bSVictor Perevertkin                         "DeviceScanSpecialDevices: Setting DEC RRD to 2K block"
1839*3088717bSVictor Perevertkin                         "size failed [%x]\n", status));
1840*3088717bSVictor Perevertkin         }
1841*3088717bSVictor Perevertkin 
1842*3088717bSVictor Perevertkin         ExFreePool(modeParameters);
1843*3088717bSVictor Perevertkin     }
1844*3088717bSVictor Perevertkin 
1845*3088717bSVictor Perevertkin     return;
1846*3088717bSVictor Perevertkin }
1847*3088717bSVictor Perevertkin 
_IRQL_requires_max_(APC_LEVEL)1848*3088717bSVictor Perevertkin _IRQL_requires_max_(APC_LEVEL)
1849*3088717bSVictor Perevertkin VOID
1850*3088717bSVictor Perevertkin ScanForSpecialHandler(
1851*3088717bSVictor Perevertkin     _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
1852*3088717bSVictor Perevertkin     _In_ ULONG_PTR               HackFlags
1853*3088717bSVictor Perevertkin     )
1854*3088717bSVictor Perevertkin {
1855*3088717bSVictor Perevertkin     PAGED_CODE();
1856*3088717bSVictor Perevertkin 
1857*3088717bSVictor Perevertkin     CLEAR_FLAG(HackFlags, CDROM_HACK_INVALID_FLAGS);
1858*3088717bSVictor Perevertkin 
1859*3088717bSVictor Perevertkin     DeviceExtension->DeviceAdditionalData.HackFlags = HackFlags;
1860*3088717bSVictor Perevertkin 
1861*3088717bSVictor Perevertkin     return;
1862*3088717bSVictor Perevertkin }
1863*3088717bSVictor Perevertkin 
1864*3088717bSVictor Perevertkin 
_IRQL_requires_max_(PASSIVE_LEVEL)1865*3088717bSVictor Perevertkin _IRQL_requires_max_(PASSIVE_LEVEL)
1866*3088717bSVictor Perevertkin NTSTATUS
1867*3088717bSVictor Perevertkin DeviceCacheDeviceInquiryData(
1868*3088717bSVictor Perevertkin     _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
1869*3088717bSVictor Perevertkin     )
1870*3088717bSVictor Perevertkin /*++
1871*3088717bSVictor Perevertkin 
1872*3088717bSVictor Perevertkin Routine Description:
1873*3088717bSVictor Perevertkin 
1874*3088717bSVictor Perevertkin     get inquiry data from device and cache it into device extension
1875*3088717bSVictor Perevertkin     The first INQUIRY command sent is with 0x24 bytes required data,
1876*3088717bSVictor Perevertkin     as ATAport driver always sends this to enumerate devices and 0x24
1877*3088717bSVictor Perevertkin     bytes is the minimum data device should return by spec.
1878*3088717bSVictor Perevertkin 
1879*3088717bSVictor Perevertkin Arguments:
1880*3088717bSVictor Perevertkin 
1881*3088717bSVictor Perevertkin     DeviceExtension - device extension.
1882*3088717bSVictor Perevertkin 
1883*3088717bSVictor Perevertkin Return Value:
1884*3088717bSVictor Perevertkin 
1885*3088717bSVictor Perevertkin     NTSTATUS.
1886*3088717bSVictor Perevertkin 
1887*3088717bSVictor Perevertkin --*/
1888*3088717bSVictor Perevertkin {
1889*3088717bSVictor Perevertkin     NTSTATUS            status = STATUS_SUCCESS;
1890*3088717bSVictor Perevertkin     SCSI_REQUEST_BLOCK  srb = {0};
1891*3088717bSVictor Perevertkin     PCDB                cdb = (PCDB)(&srb.Cdb);
1892*3088717bSVictor Perevertkin     PINQUIRYDATA        tmpInquiry = NULL;
1893*3088717bSVictor Perevertkin 
1894*3088717bSVictor Perevertkin     // by spec, device should return at least 36 bytes.
1895*3088717bSVictor Perevertkin     ULONG               requestedInquiryTransferBytes = MINIMUM_CDROM_INQUIRY_SIZE;
1896*3088717bSVictor Perevertkin     BOOLEAN             needResendCommand = TRUE;
1897*3088717bSVictor Perevertkin     BOOLEAN             portDriverHack = FALSE;
1898*3088717bSVictor Perevertkin 
1899*3088717bSVictor Perevertkin     // this ensures that the strings vendorID, productID, and firmwareRevision
1900*3088717bSVictor Perevertkin     // are all available in the inquiry data.  In addition, MMC spec requires
1901*3088717bSVictor Perevertkin     // all type 5 devices to have minimum 36 bytes of inquiry.
1902*3088717bSVictor Perevertkin     static const UCHAR minInquiryAdditionalLength =
1903*3088717bSVictor Perevertkin                                     MINIMUM_CDROM_INQUIRY_SIZE -
1904*3088717bSVictor Perevertkin                                     RTL_SIZEOF_THROUGH_FIELD(INQUIRYDATA, AdditionalLength);
1905*3088717bSVictor Perevertkin 
1906*3088717bSVictor Perevertkin     C_ASSERT( RTL_SIZEOF_THROUGH_FIELD(INQUIRYDATA, AdditionalLength) <= 8 );
1907*3088717bSVictor Perevertkin     C_ASSERT( RTL_SIZEOF_THROUGH_FIELD(INQUIRYDATA, ProductRevisionLevel) == MINIMUM_CDROM_INQUIRY_SIZE );
1908*3088717bSVictor Perevertkin 
1909*3088717bSVictor Perevertkin     PAGED_CODE();
1910*3088717bSVictor Perevertkin 
1911*3088717bSVictor Perevertkin     // short-circuit here for if already cached for this device
1912*3088717bSVictor Perevertkin     // required to avoid use of scratch buffer after initialization
1913*3088717bSVictor Perevertkin     // of MCN code.
1914*3088717bSVictor Perevertkin     if (DeviceExtension->DeviceAdditionalData.CachedInquiryData != NULL)
1915*3088717bSVictor Perevertkin     {
1916*3088717bSVictor Perevertkin         NT_ASSERT(DeviceExtension->DeviceAdditionalData.CachedInquiryDataByteCount != 0);
1917*3088717bSVictor Perevertkin         return STATUS_SUCCESS;
1918*3088717bSVictor Perevertkin     }
1919*3088717bSVictor Perevertkin 
1920*3088717bSVictor Perevertkin     // 1. retrieve the inquiry data length
1921*3088717bSVictor Perevertkin 
1922*3088717bSVictor Perevertkin     // 1.1 allocate inquiry data buffer
1923*3088717bSVictor Perevertkin     tmpInquiry = ExAllocatePoolWithTag(NonPagedPoolNx,
1924*3088717bSVictor Perevertkin                                        requestedInquiryTransferBytes,
1925*3088717bSVictor Perevertkin                                        CDROM_TAG_INQUIRY);
1926*3088717bSVictor Perevertkin     if (tmpInquiry == NULL)
1927*3088717bSVictor Perevertkin     {
1928*3088717bSVictor Perevertkin         status = STATUS_INSUFFICIENT_RESOURCES;
1929*3088717bSVictor Perevertkin     }
1930*3088717bSVictor Perevertkin 
1931*3088717bSVictor Perevertkin     // 1.2 send INQUIRY command
1932*3088717bSVictor Perevertkin     if (NT_SUCCESS(status))
1933*3088717bSVictor Perevertkin     {
1934*3088717bSVictor Perevertkin         srb.CdbLength = 6;
1935*3088717bSVictor Perevertkin         cdb->AsByte[0] = SCSIOP_INQUIRY;
1936*3088717bSVictor Perevertkin         cdb->AsByte[3] = (UCHAR)( requestedInquiryTransferBytes >> (8*1) );
1937*3088717bSVictor Perevertkin         cdb->AsByte[4] = (UCHAR)( requestedInquiryTransferBytes >> (8*0) );
1938*3088717bSVictor Perevertkin 
1939*3088717bSVictor Perevertkin         status = DeviceSendSrbSynchronously(DeviceExtension->Device,
1940*3088717bSVictor Perevertkin                                             &srb,
1941*3088717bSVictor Perevertkin                                             tmpInquiry,
1942*3088717bSVictor Perevertkin                                             requestedInquiryTransferBytes,
1943*3088717bSVictor Perevertkin                                             FALSE,
1944*3088717bSVictor Perevertkin                                             NULL);
1945*3088717bSVictor Perevertkin     }
1946*3088717bSVictor Perevertkin 
1947*3088717bSVictor Perevertkin     // 1.3 get required data length
1948*3088717bSVictor Perevertkin     if (NT_SUCCESS(status))
1949*3088717bSVictor Perevertkin     {
1950*3088717bSVictor Perevertkin         if ((requestedInquiryTransferBytes == srb.DataTransferLength) &&
1951*3088717bSVictor Perevertkin             (requestedInquiryTransferBytes == (tmpInquiry->AdditionalLength +
1952*3088717bSVictor Perevertkin                                                RTL_SIZEOF_THROUGH_FIELD(INQUIRYDATA, AdditionalLength))) )
1953*3088717bSVictor Perevertkin         {
1954*3088717bSVictor Perevertkin             // device has only 36 bytes of INQUIRY data. do not need to resend the command.
1955*3088717bSVictor Perevertkin             needResendCommand = FALSE;
1956*3088717bSVictor Perevertkin         }
1957*3088717bSVictor Perevertkin         else
1958*3088717bSVictor Perevertkin         {
1959*3088717bSVictor Perevertkin             // workaround an ATAPI.SYS bug where additional length field is set to zero
1960*3088717bSVictor Perevertkin             if (tmpInquiry->AdditionalLength == 0)
1961*3088717bSVictor Perevertkin             {
1962*3088717bSVictor Perevertkin                 tmpInquiry->AdditionalLength = minInquiryAdditionalLength;
1963*3088717bSVictor Perevertkin                 portDriverHack = TRUE;
1964*3088717bSVictor Perevertkin             }
1965*3088717bSVictor Perevertkin 
1966*3088717bSVictor Perevertkin             requestedInquiryTransferBytes =
1967*3088717bSVictor Perevertkin                                 tmpInquiry->AdditionalLength +
1968*3088717bSVictor Perevertkin                                 RTL_SIZEOF_THROUGH_FIELD(INQUIRYDATA, AdditionalLength);
1969*3088717bSVictor Perevertkin 
1970*3088717bSVictor Perevertkin             if (requestedInquiryTransferBytes >= MINIMUM_CDROM_INQUIRY_SIZE)
1971*3088717bSVictor Perevertkin             {
1972*3088717bSVictor Perevertkin                 needResendCommand = TRUE;
1973*3088717bSVictor Perevertkin             }
1974*3088717bSVictor Perevertkin             else
1975*3088717bSVictor Perevertkin             {
1976*3088717bSVictor Perevertkin                 needResendCommand = FALSE;
1977*3088717bSVictor Perevertkin                 //Length is small than minimum length, error out.
1978*3088717bSVictor Perevertkin                 status = STATUS_DEVICE_PROTOCOL_ERROR;
1979*3088717bSVictor Perevertkin             }
1980*3088717bSVictor Perevertkin         }
1981*3088717bSVictor Perevertkin     }
1982*3088717bSVictor Perevertkin 
1983*3088717bSVictor Perevertkin     // 2. retrieve the inquiry data if still needed.
1984*3088717bSVictor Perevertkin 
1985*3088717bSVictor Perevertkin     // 2.1 Clean up.
1986*3088717bSVictor Perevertkin     if (NT_SUCCESS(status) && needResendCommand)
1987*3088717bSVictor Perevertkin     {
1988*3088717bSVictor Perevertkin         FREE_POOL(tmpInquiry);
1989*3088717bSVictor Perevertkin         RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
1990*3088717bSVictor Perevertkin 
1991*3088717bSVictor Perevertkin         tmpInquiry = ExAllocatePoolWithTag(NonPagedPoolNx,
1992*3088717bSVictor Perevertkin                                            requestedInquiryTransferBytes,
1993*3088717bSVictor Perevertkin                                            CDROM_TAG_INQUIRY);
1994*3088717bSVictor Perevertkin         if (tmpInquiry == NULL)
1995*3088717bSVictor Perevertkin         {
1996*3088717bSVictor Perevertkin             status = STATUS_INSUFFICIENT_RESOURCES;
1997*3088717bSVictor Perevertkin         }
1998*3088717bSVictor Perevertkin     }
1999*3088717bSVictor Perevertkin 
2000*3088717bSVictor Perevertkin     // 2.2 resend INQUIRY command
2001*3088717bSVictor Perevertkin     if (NT_SUCCESS(status) && needResendCommand)
2002*3088717bSVictor Perevertkin     {
2003*3088717bSVictor Perevertkin         srb.CdbLength = 6;
2004*3088717bSVictor Perevertkin         cdb->AsByte[0] = SCSIOP_INQUIRY;
2005*3088717bSVictor Perevertkin         cdb->AsByte[3] = (UCHAR)( requestedInquiryTransferBytes >> (8*1) );
2006*3088717bSVictor Perevertkin         cdb->AsByte[4] = (UCHAR)( requestedInquiryTransferBytes >> (8*0) );
2007*3088717bSVictor Perevertkin 
2008*3088717bSVictor Perevertkin         status = DeviceSendSrbSynchronously( DeviceExtension->Device,
2009*3088717bSVictor Perevertkin                                              &srb,
2010*3088717bSVictor Perevertkin                                              tmpInquiry,
2011*3088717bSVictor Perevertkin                                              requestedInquiryTransferBytes,
2012*3088717bSVictor Perevertkin                                              FALSE,
2013*3088717bSVictor Perevertkin                                              NULL);
2014*3088717bSVictor Perevertkin 
2015*3088717bSVictor Perevertkin         if (!NT_SUCCESS(status))
2016*3088717bSVictor Perevertkin         {
2017*3088717bSVictor Perevertkin             // Workaround for drive reports that it has more INQUIRY data than reality.
2018*3088717bSVictor Perevertkin             if ((srb.SrbStatus == SRB_STATUS_DATA_OVERRUN) &&
2019*3088717bSVictor Perevertkin                 (srb.DataTransferLength < requestedInquiryTransferBytes) &&
2020*3088717bSVictor Perevertkin                 (srb.DataTransferLength >= MINIMUM_CDROM_INQUIRY_SIZE))
2021*3088717bSVictor Perevertkin             {
2022*3088717bSVictor Perevertkin                 //Port driver says buffer size mismatch (buffer underrun),
2023*3088717bSVictor Perevertkin                 //retry with the real buffer size it could return.
2024*3088717bSVictor Perevertkin                 requestedInquiryTransferBytes = srb.DataTransferLength;
2025*3088717bSVictor Perevertkin 
2026*3088717bSVictor Perevertkin                 FREE_POOL(tmpInquiry);
2027*3088717bSVictor Perevertkin                 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
2028*3088717bSVictor Perevertkin 
2029*3088717bSVictor Perevertkin                 tmpInquiry = ExAllocatePoolWithTag(NonPagedPoolNx,
2030*3088717bSVictor Perevertkin                                                    requestedInquiryTransferBytes,
2031*3088717bSVictor Perevertkin                                                    CDROM_TAG_INQUIRY);
2032*3088717bSVictor Perevertkin                 if (tmpInquiry == NULL)
2033*3088717bSVictor Perevertkin                 {
2034*3088717bSVictor Perevertkin                     status = STATUS_INSUFFICIENT_RESOURCES;
2035*3088717bSVictor Perevertkin                 }
2036*3088717bSVictor Perevertkin                 else
2037*3088717bSVictor Perevertkin                 {
2038*3088717bSVictor Perevertkin                     srb.CdbLength = 6;
2039*3088717bSVictor Perevertkin                     cdb->AsByte[0] = SCSIOP_INQUIRY;
2040*3088717bSVictor Perevertkin                     cdb->AsByte[3] = (UCHAR)( requestedInquiryTransferBytes >> (8*1) );
2041*3088717bSVictor Perevertkin                     cdb->AsByte[4] = (UCHAR)( requestedInquiryTransferBytes >> (8*0) );
2042*3088717bSVictor Perevertkin 
2043*3088717bSVictor Perevertkin                     status = DeviceSendSrbSynchronously(DeviceExtension->Device,
2044*3088717bSVictor Perevertkin                                                         &srb,
2045*3088717bSVictor Perevertkin                                                         tmpInquiry,
2046*3088717bSVictor Perevertkin                                                         requestedInquiryTransferBytes,
2047*3088717bSVictor Perevertkin                                                         FALSE,
2048*3088717bSVictor Perevertkin                                                         NULL);
2049*3088717bSVictor Perevertkin                 }
2050*3088717bSVictor Perevertkin             }
2051*3088717bSVictor Perevertkin         }
2052*3088717bSVictor Perevertkin 
2053*3088717bSVictor Perevertkin         //Check the transferred data length for safe.
2054*3088717bSVictor Perevertkin         if (NT_SUCCESS(status))
2055*3088717bSVictor Perevertkin         {
2056*3088717bSVictor Perevertkin             requestedInquiryTransferBytes = srb.DataTransferLength;
2057*3088717bSVictor Perevertkin 
2058*3088717bSVictor Perevertkin             if (requestedInquiryTransferBytes < MINIMUM_CDROM_INQUIRY_SIZE)
2059*3088717bSVictor Perevertkin             {
2060*3088717bSVictor Perevertkin                 // should never occur
2061*3088717bSVictor Perevertkin                 status = STATUS_DEVICE_PROTOCOL_ERROR;
2062*3088717bSVictor Perevertkin             }
2063*3088717bSVictor Perevertkin         }
2064*3088717bSVictor Perevertkin 
2065*3088717bSVictor Perevertkin         // ensure we got some non-zero data....
2066*3088717bSVictor Perevertkin         // This is done so we don't accidentally work around the
2067*3088717bSVictor Perevertkin         // ATAPI.SYS bug when no data was transferred.
2068*3088717bSVictor Perevertkin         if (NT_SUCCESS(status) && portDriverHack)
2069*3088717bSVictor Perevertkin         {
2070*3088717bSVictor Perevertkin             PULONG  tmp = (PULONG)tmpInquiry;
2071*3088717bSVictor Perevertkin             ULONG   i = MINIMUM_CDROM_INQUIRY_SIZE / sizeof(ULONG);
2072*3088717bSVictor Perevertkin             C_ASSERT( RTL_SIZEOF_THROUGH_FIELD(INQUIRYDATA, ProductRevisionLevel) % sizeof(ULONG) == 0 );
2073*3088717bSVictor Perevertkin 
2074*3088717bSVictor Perevertkin             // wouldn't you know it -- there is no RtlIsMemoryZero() function; Make one up.
2075*3088717bSVictor Perevertkin             for ( ; i != 0; i--)
2076*3088717bSVictor Perevertkin             {
2077*3088717bSVictor Perevertkin                 if (*tmp != 0)
2078*3088717bSVictor Perevertkin                 {
2079*3088717bSVictor Perevertkin                     break; // out of this inner FOR loop -- guarantees 'i != 0'
2080*3088717bSVictor Perevertkin                 }
2081*3088717bSVictor Perevertkin                 tmp++;
2082*3088717bSVictor Perevertkin             }
2083*3088717bSVictor Perevertkin 
2084*3088717bSVictor Perevertkin             if (i == 0) // all loop'd successfully
2085*3088717bSVictor Perevertkin             {
2086*3088717bSVictor Perevertkin                 // should never occur to successfully get all zero'd data
2087*3088717bSVictor Perevertkin                 status = STATUS_DEVICE_PROTOCOL_ERROR;
2088*3088717bSVictor Perevertkin             }
2089*3088717bSVictor Perevertkin         }
2090*3088717bSVictor Perevertkin     }
2091*3088717bSVictor Perevertkin 
2092*3088717bSVictor Perevertkin     // if everything succeeded, then (and only then) modify the device extension
2093*3088717bSVictor Perevertkin     if (NT_SUCCESS(status))
2094*3088717bSVictor Perevertkin     {
2095*3088717bSVictor Perevertkin         DeviceExtension->DeviceAdditionalData.CachedInquiryData = tmpInquiry;
2096*3088717bSVictor Perevertkin         DeviceExtension->DeviceAdditionalData.CachedInquiryDataByteCount = requestedInquiryTransferBytes;
2097*3088717bSVictor Perevertkin     }
2098*3088717bSVictor Perevertkin     else
2099*3088717bSVictor Perevertkin     {
2100*3088717bSVictor Perevertkin         FREE_POOL(tmpInquiry);
2101*3088717bSVictor Perevertkin     }
2102*3088717bSVictor Perevertkin 
2103*3088717bSVictor Perevertkin     return status;
2104*3088717bSVictor Perevertkin }
2105*3088717bSVictor Perevertkin 
_IRQL_requires_max_(PASSIVE_LEVEL)2106*3088717bSVictor Perevertkin _IRQL_requires_max_(PASSIVE_LEVEL)
2107*3088717bSVictor Perevertkin NTSTATUS
2108*3088717bSVictor Perevertkin DeviceGetMmcSupportInfo(
2109*3088717bSVictor Perevertkin     _In_  PCDROM_DEVICE_EXTENSION   DeviceExtension,
2110*3088717bSVictor Perevertkin     _Out_ PBOOLEAN                  IsMmcDevice
2111*3088717bSVictor Perevertkin     )
2112*3088717bSVictor Perevertkin /*++
2113*3088717bSVictor Perevertkin 
2114*3088717bSVictor Perevertkin Routine Description:
2115*3088717bSVictor Perevertkin 
2116*3088717bSVictor Perevertkin     check if the device is MMC capable.
2117*3088717bSVictor Perevertkin 
2118*3088717bSVictor Perevertkin Arguments:
2119*3088717bSVictor Perevertkin 
2120*3088717bSVictor Perevertkin     DeviceExtension - device extension.
2121*3088717bSVictor Perevertkin 
2122*3088717bSVictor Perevertkin Return Value:
2123*3088717bSVictor Perevertkin 
2124*3088717bSVictor Perevertkin     NTSTATUS.
2125*3088717bSVictor Perevertkin     IsMmcDevice - TRUE (MMC capable); FALSE (not MMC device)
2126*3088717bSVictor Perevertkin 
2127*3088717bSVictor Perevertkin --*/
2128*3088717bSVictor Perevertkin {
2129*3088717bSVictor Perevertkin     NTSTATUS    status;
2130*3088717bSVictor Perevertkin     ULONG       size;
2131*3088717bSVictor Perevertkin     ULONG       previouslyFailed;
2132*3088717bSVictor Perevertkin 
2133*3088717bSVictor Perevertkin     PAGED_CODE();
2134*3088717bSVictor Perevertkin 
2135*3088717bSVictor Perevertkin     *IsMmcDevice  = FALSE;
2136*3088717bSVictor Perevertkin 
2137*3088717bSVictor Perevertkin     // read the registry in case the drive failed previously,
2138*3088717bSVictor Perevertkin     // and a timeout is occurring.
2139*3088717bSVictor Perevertkin     previouslyFailed = FALSE;
2140*3088717bSVictor Perevertkin     DeviceGetParameter(DeviceExtension,
2141*3088717bSVictor Perevertkin                        CDROM_SUBKEY_NAME,
2142*3088717bSVictor Perevertkin                        CDROM_NON_MMC_DRIVE_NAME,
2143*3088717bSVictor Perevertkin                        &previouslyFailed);
2144*3088717bSVictor Perevertkin 
2145*3088717bSVictor Perevertkin     if (previouslyFailed)
2146*3088717bSVictor Perevertkin     {
2147*3088717bSVictor Perevertkin         SET_FLAG(DeviceExtension->DeviceAdditionalData.HackFlags, CDROM_HACK_BAD_GET_CONFIG_SUPPORT);
2148*3088717bSVictor Perevertkin     }
2149*3088717bSVictor Perevertkin 
2150*3088717bSVictor Perevertkin     // read from the registry in case the drive reports bad profile lengths
2151*3088717bSVictor Perevertkin     previouslyFailed = FALSE;
2152*3088717bSVictor Perevertkin     DeviceGetParameter(DeviceExtension,
2153*3088717bSVictor Perevertkin                        CDROM_SUBKEY_NAME,
2154*3088717bSVictor Perevertkin                        CDROM_NON_MMC_VENDOR_SPECIFIC_PROFILE,
2155*3088717bSVictor Perevertkin                        &previouslyFailed);
2156*3088717bSVictor Perevertkin 
2157*3088717bSVictor Perevertkin     if (previouslyFailed)
2158*3088717bSVictor Perevertkin     {
2159*3088717bSVictor Perevertkin         SET_FLAG(DeviceExtension->DeviceAdditionalData.HackFlags, CDROM_HACK_BAD_VENDOR_PROFILES);
2160*3088717bSVictor Perevertkin     }
2161*3088717bSVictor Perevertkin 
2162*3088717bSVictor Perevertkin     // check for the ProfileList feature to determine if the drive is MMC compliant
2163*3088717bSVictor Perevertkin     // and set the "size" local variable to total GetConfig data size available.
2164*3088717bSVictor Perevertkin     // NOTE: This will exit this function in some error paths.
2165*3088717bSVictor Perevertkin     {
2166*3088717bSVictor Perevertkin         GET_CONFIGURATION_HEADER    localHeader = {0};
2167*3088717bSVictor Perevertkin         ULONG                       usable = 0;
2168*3088717bSVictor Perevertkin 
2169*3088717bSVictor Perevertkin         status = DeviceGetConfiguration(DeviceExtension->Device,
2170*3088717bSVictor Perevertkin                                         &localHeader,
2171*3088717bSVictor Perevertkin                                         sizeof(GET_CONFIGURATION_HEADER),
2172*3088717bSVictor Perevertkin                                         &usable,
2173*3088717bSVictor Perevertkin                                         FeatureProfileList,
2174*3088717bSVictor Perevertkin                                         SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL);
2175*3088717bSVictor Perevertkin 
2176*3088717bSVictor Perevertkin         if (status == STATUS_INVALID_DEVICE_REQUEST ||
2177*3088717bSVictor Perevertkin             status == STATUS_NO_MEDIA_IN_DEVICE     ||
2178*3088717bSVictor Perevertkin             status == STATUS_IO_DEVICE_ERROR        ||
2179*3088717bSVictor Perevertkin             status == STATUS_IO_TIMEOUT)
2180*3088717bSVictor Perevertkin         {
2181*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT,
2182*3088717bSVictor Perevertkin                        "GetConfiguration Failed (%x), device %p not mmc-compliant\n",
2183*3088717bSVictor Perevertkin                        status, DeviceExtension->DeviceObject
2184*3088717bSVictor Perevertkin                        ));
2185*3088717bSVictor Perevertkin 
2186*3088717bSVictor Perevertkin             previouslyFailed = TRUE;
2187*3088717bSVictor Perevertkin             DeviceSetParameter( DeviceExtension,
2188*3088717bSVictor Perevertkin                                 CDROM_SUBKEY_NAME,
2189*3088717bSVictor Perevertkin                                 CDROM_NON_MMC_DRIVE_NAME,
2190*3088717bSVictor Perevertkin                                 previouslyFailed);
2191*3088717bSVictor Perevertkin 
2192*3088717bSVictor Perevertkin             return STATUS_SUCCESS;
2193*3088717bSVictor Perevertkin         }
2194*3088717bSVictor Perevertkin         else if (!NT_SUCCESS(status))
2195*3088717bSVictor Perevertkin         {
2196*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT,
2197*3088717bSVictor Perevertkin                        "GetConfiguration Failed, status %x -- defaulting to -ROM\n",
2198*3088717bSVictor Perevertkin                        status));
2199*3088717bSVictor Perevertkin 
2200*3088717bSVictor Perevertkin             return STATUS_SUCCESS;
2201*3088717bSVictor Perevertkin         }
2202*3088717bSVictor Perevertkin         else if (usable < sizeof(GET_CONFIGURATION_HEADER))
2203*3088717bSVictor Perevertkin         {
2204*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT,
2205*3088717bSVictor Perevertkin                        "GetConfiguration Failed, returned only %x bytes!\n", usable));
2206*3088717bSVictor Perevertkin             previouslyFailed = TRUE;
2207*3088717bSVictor Perevertkin             DeviceSetParameter( DeviceExtension,
2208*3088717bSVictor Perevertkin                                 CDROM_SUBKEY_NAME,
2209*3088717bSVictor Perevertkin                                 CDROM_NON_MMC_DRIVE_NAME,
2210*3088717bSVictor Perevertkin                                 previouslyFailed);
2211*3088717bSVictor Perevertkin 
2212*3088717bSVictor Perevertkin             return STATUS_SUCCESS;
2213*3088717bSVictor Perevertkin         }
2214*3088717bSVictor Perevertkin 
2215*3088717bSVictor Perevertkin         size = (localHeader.DataLength[0] << 24) |
2216*3088717bSVictor Perevertkin                (localHeader.DataLength[1] << 16) |
2217*3088717bSVictor Perevertkin                (localHeader.DataLength[2] <<  8) |
2218*3088717bSVictor Perevertkin                (localHeader.DataLength[3] <<  0) ;
2219*3088717bSVictor Perevertkin 
2220*3088717bSVictor Perevertkin 
2221*3088717bSVictor Perevertkin         if ((size <= 4) || (size + 4 < size))
2222*3088717bSVictor Perevertkin         {
2223*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT,
2224*3088717bSVictor Perevertkin                        "GetConfiguration Failed, claims MMC support but doesn't "
2225*3088717bSVictor Perevertkin                        "correctly return config length! (%x)\n",
2226*3088717bSVictor Perevertkin                        size
2227*3088717bSVictor Perevertkin                        ));
2228*3088717bSVictor Perevertkin             previouslyFailed = TRUE;
2229*3088717bSVictor Perevertkin             DeviceSetParameter( DeviceExtension,
2230*3088717bSVictor Perevertkin                                 CDROM_SUBKEY_NAME,
2231*3088717bSVictor Perevertkin                                 CDROM_NON_MMC_DRIVE_NAME,
2232*3088717bSVictor Perevertkin                                 previouslyFailed);
2233*3088717bSVictor Perevertkin 
2234*3088717bSVictor Perevertkin             return STATUS_SUCCESS;
2235*3088717bSVictor Perevertkin         }
2236*3088717bSVictor Perevertkin         else if ((size % 4) != 0)
2237*3088717bSVictor Perevertkin         {
2238*3088717bSVictor Perevertkin             if ((size % 2) != 0)
2239*3088717bSVictor Perevertkin             {
2240*3088717bSVictor Perevertkin                 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT,
2241*3088717bSVictor Perevertkin                            "GetConfiguration Failed, returned odd number of bytes %x!\n",
2242*3088717bSVictor Perevertkin                            size
2243*3088717bSVictor Perevertkin                            ));
2244*3088717bSVictor Perevertkin                 previouslyFailed = TRUE;
2245*3088717bSVictor Perevertkin                 DeviceSetParameter( DeviceExtension,
2246*3088717bSVictor Perevertkin                                     CDROM_SUBKEY_NAME,
2247*3088717bSVictor Perevertkin                                     CDROM_NON_MMC_DRIVE_NAME,
2248*3088717bSVictor Perevertkin                                     previouslyFailed);
2249*3088717bSVictor Perevertkin 
2250*3088717bSVictor Perevertkin                 return STATUS_SUCCESS;
2251*3088717bSVictor Perevertkin             }
2252*3088717bSVictor Perevertkin             else
2253*3088717bSVictor Perevertkin             {
2254*3088717bSVictor Perevertkin                 if (TEST_FLAG(DeviceExtension->DeviceAdditionalData.HackFlags, CDROM_HACK_BAD_VENDOR_PROFILES))
2255*3088717bSVictor Perevertkin                 {
2256*3088717bSVictor Perevertkin                     // we've already caught this and ASSERT'd once, so don't do it again
2257*3088717bSVictor Perevertkin                 }
2258*3088717bSVictor Perevertkin                 else
2259*3088717bSVictor Perevertkin                 {
2260*3088717bSVictor Perevertkin                     TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT,
2261*3088717bSVictor Perevertkin                                "GetConfiguration returned a size that is not per spec (%x bytes), this is probably because of a vendor specific data header with a size not divisible by 4.\n",
2262*3088717bSVictor Perevertkin                                size
2263*3088717bSVictor Perevertkin                                ));
2264*3088717bSVictor Perevertkin                     previouslyFailed = TRUE;
2265*3088717bSVictor Perevertkin                     DeviceSetParameter(DeviceExtension,
2266*3088717bSVictor Perevertkin                                        CDROM_SUBKEY_NAME,
2267*3088717bSVictor Perevertkin                                        CDROM_NON_MMC_VENDOR_SPECIFIC_PROFILE,
2268*3088717bSVictor Perevertkin                                        previouslyFailed);
2269*3088717bSVictor Perevertkin                 }
2270*3088717bSVictor Perevertkin             }
2271*3088717bSVictor Perevertkin         }
2272*3088717bSVictor Perevertkin 
2273*3088717bSVictor Perevertkin         size += 4; // sizeof the datalength fields
2274*3088717bSVictor Perevertkin     }
2275*3088717bSVictor Perevertkin 
2276*3088717bSVictor Perevertkin     *IsMmcDevice = TRUE;
2277*3088717bSVictor Perevertkin 
2278*3088717bSVictor Perevertkin     // This code doesn't handle total get config size over 64k
2279*3088717bSVictor Perevertkin     NT_ASSERT( size <= MAXUSHORT );
2280*3088717bSVictor Perevertkin 
2281*3088717bSVictor Perevertkin     // Check for SCSI_GET_CONFIGURATION_REQUEST_TYPE_ONE support in the device.
2282*3088717bSVictor Perevertkin     // NOTE: This will exit this function in some error paths.
2283*3088717bSVictor Perevertkin     {
2284*3088717bSVictor Perevertkin         ULONG   featureSize = sizeof(GET_CONFIGURATION_HEADER)+sizeof(FEATURE_HEADER);
2285*3088717bSVictor Perevertkin         ULONG   usable = 0;
2286*3088717bSVictor Perevertkin 
2287*3088717bSVictor Perevertkin         PGET_CONFIGURATION_HEADER configBuffer = ExAllocatePoolWithTag(
2288*3088717bSVictor Perevertkin                                                             NonPagedPoolNx,
2289*3088717bSVictor Perevertkin                                                             featureSize,
2290*3088717bSVictor Perevertkin                                                             CDROM_TAG_GET_CONFIG);
2291*3088717bSVictor Perevertkin 
2292*3088717bSVictor Perevertkin         if (configBuffer == NULL)
2293*3088717bSVictor Perevertkin         {
2294*3088717bSVictor Perevertkin             return STATUS_INSUFFICIENT_RESOURCES;
2295*3088717bSVictor Perevertkin         }
2296*3088717bSVictor Perevertkin 
2297*3088717bSVictor Perevertkin         // read the registry in case the drive failed previously,
2298*3088717bSVictor Perevertkin         // and a timeout is occurring.
2299*3088717bSVictor Perevertkin         previouslyFailed = FALSE;
2300*3088717bSVictor Perevertkin         DeviceGetParameter( DeviceExtension,
2301*3088717bSVictor Perevertkin                             CDROM_SUBKEY_NAME,
2302*3088717bSVictor Perevertkin                             CDROM_TYPE_ONE_GET_CONFIG_NAME,
2303*3088717bSVictor Perevertkin                             &previouslyFailed);
2304*3088717bSVictor Perevertkin 
2305*3088717bSVictor Perevertkin         if (previouslyFailed)
2306*3088717bSVictor Perevertkin         {
2307*3088717bSVictor Perevertkin             SET_FLAG(DeviceExtension->DeviceAdditionalData.HackFlags, CDROM_HACK_BAD_TYPE_ONE_GET_CONFIG);
2308*3088717bSVictor Perevertkin             FREE_POOL(configBuffer);
2309*3088717bSVictor Perevertkin             return STATUS_SUCCESS;
2310*3088717bSVictor Perevertkin         }
2311*3088717bSVictor Perevertkin 
2312*3088717bSVictor Perevertkin         // Get only the config and feature header
2313*3088717bSVictor Perevertkin         status = DeviceGetConfiguration(DeviceExtension->Device,
2314*3088717bSVictor Perevertkin                                         configBuffer,
2315*3088717bSVictor Perevertkin                                         featureSize,
2316*3088717bSVictor Perevertkin                                         &usable,
2317*3088717bSVictor Perevertkin                                         FeatureProfileList,
2318*3088717bSVictor Perevertkin                                         SCSI_GET_CONFIGURATION_REQUEST_TYPE_ONE);
2319*3088717bSVictor Perevertkin 
2320*3088717bSVictor Perevertkin         if (!NT_SUCCESS(status) || (usable < featureSize))
2321*3088717bSVictor Perevertkin         {
2322*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT,
2323*3088717bSVictor Perevertkin                        "Type One GetConfiguration Failed. Usable buffer size: %d\n", usable));
2324*3088717bSVictor Perevertkin             previouslyFailed = TRUE;
2325*3088717bSVictor Perevertkin         }
2326*3088717bSVictor Perevertkin         else
2327*3088717bSVictor Perevertkin         {
2328*3088717bSVictor Perevertkin             PFEATURE_HEADER featureHeader;
2329*3088717bSVictor Perevertkin             ULONG           totalAvailableBytes = 0;
2330*3088717bSVictor Perevertkin             ULONG           expectedAvailableBytes = 0;
2331*3088717bSVictor Perevertkin 
2332*3088717bSVictor Perevertkin             REVERSE_BYTES(&totalAvailableBytes, configBuffer->DataLength);
2333*3088717bSVictor Perevertkin             totalAvailableBytes += RTL_SIZEOF_THROUGH_FIELD(GET_CONFIGURATION_HEADER, DataLength);
2334*3088717bSVictor Perevertkin 
2335*3088717bSVictor Perevertkin             featureHeader = (PFEATURE_HEADER) ((PUCHAR)configBuffer + sizeof(GET_CONFIGURATION_HEADER));
2336*3088717bSVictor Perevertkin             expectedAvailableBytes = sizeof(GET_CONFIGURATION_HEADER) +
2337*3088717bSVictor Perevertkin                                      sizeof(FEATURE_HEADER) +
2338*3088717bSVictor Perevertkin                                      featureHeader->AdditionalLength;
2339*3088717bSVictor Perevertkin 
2340*3088717bSVictor Perevertkin             if (totalAvailableBytes > expectedAvailableBytes)
2341*3088717bSVictor Perevertkin             {
2342*3088717bSVictor Perevertkin                 // Device is returning more than required size. Most likely the device
2343*3088717bSVictor Perevertkin                 // is returning TYPE ALL data. Set the flag to use TYPE ALL for TYPE ONE
2344*3088717bSVictor Perevertkin                 // requets
2345*3088717bSVictor Perevertkin                 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT,
2346*3088717bSVictor Perevertkin                            "Type One GetConfiguration Failed. "
2347*3088717bSVictor Perevertkin                            "Device returned %d bytes instead of %d bytes\n",
2348*3088717bSVictor Perevertkin                            size, featureSize));
2349*3088717bSVictor Perevertkin 
2350*3088717bSVictor Perevertkin                 previouslyFailed = TRUE;
2351*3088717bSVictor Perevertkin             }
2352*3088717bSVictor Perevertkin         }
2353*3088717bSVictor Perevertkin 
2354*3088717bSVictor Perevertkin         FREE_POOL(configBuffer);
2355*3088717bSVictor Perevertkin 
2356*3088717bSVictor Perevertkin         if (previouslyFailed == TRUE)
2357*3088717bSVictor Perevertkin         {
2358*3088717bSVictor Perevertkin             DeviceSetParameter( DeviceExtension,
2359*3088717bSVictor Perevertkin                                 CDROM_SUBKEY_NAME,
2360*3088717bSVictor Perevertkin                                 CDROM_TYPE_ONE_GET_CONFIG_NAME,
2361*3088717bSVictor Perevertkin                                 previouslyFailed);
2362*3088717bSVictor Perevertkin 
2363*3088717bSVictor Perevertkin             SET_FLAG(DeviceExtension->DeviceAdditionalData.HackFlags, CDROM_HACK_BAD_TYPE_ONE_GET_CONFIG);
2364*3088717bSVictor Perevertkin         }
2365*3088717bSVictor Perevertkin     }
2366*3088717bSVictor Perevertkin 
2367*3088717bSVictor Perevertkin     return status;
2368*3088717bSVictor Perevertkin }
2369*3088717bSVictor Perevertkin 
2370*3088717bSVictor Perevertkin 
_IRQL_requires_max_(APC_LEVEL)2371*3088717bSVictor Perevertkin _IRQL_requires_max_(APC_LEVEL)
2372*3088717bSVictor Perevertkin NTSTATUS
2373*3088717bSVictor Perevertkin DeviceSetRawReadInfo(
2374*3088717bSVictor Perevertkin     _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
2375*3088717bSVictor Perevertkin     )
2376*3088717bSVictor Perevertkin /*++
2377*3088717bSVictor Perevertkin 
2378*3088717bSVictor Perevertkin Routine Description:
2379*3088717bSVictor Perevertkin 
2380*3088717bSVictor Perevertkin     This routine reads the CDROM capabilities mode page and save information
2381*3088717bSVictor Perevertkin     in the device extension needed for raw reads.
2382*3088717bSVictor Perevertkin     NOTE: this function is only valid for MMC device
2383*3088717bSVictor Perevertkin 
2384*3088717bSVictor Perevertkin Arguments:
2385*3088717bSVictor Perevertkin 
2386*3088717bSVictor Perevertkin     DeviceExtension - device context
2387*3088717bSVictor Perevertkin 
2388*3088717bSVictor Perevertkin Return Value:
2389*3088717bSVictor Perevertkin 
2390*3088717bSVictor Perevertkin     NTSTATUS
2391*3088717bSVictor Perevertkin 
2392*3088717bSVictor Perevertkin --*/
2393*3088717bSVictor Perevertkin {
2394*3088717bSVictor Perevertkin     NTSTATUS    status = STATUS_SUCCESS;
2395*3088717bSVictor Perevertkin     PUCHAR      buffer = NULL;
2396*3088717bSVictor Perevertkin     ULONG       count = 0;
2397*3088717bSVictor Perevertkin 
2398*3088717bSVictor Perevertkin     PAGED_CODE();
2399*3088717bSVictor Perevertkin 
2400*3088717bSVictor Perevertkin     // Check whether the device can return C2 error flag bits and the block
2401*3088717bSVictor Perevertkin     // error byte.  If so, save this info and fill in appropriate flag during
2402*3088717bSVictor Perevertkin     // raw read requests.
2403*3088717bSVictor Perevertkin 
2404*3088717bSVictor Perevertkin     // Start by checking the GET_CONFIGURATION data
2405*3088717bSVictor Perevertkin     {
2406*3088717bSVictor Perevertkin         PFEATURE_DATA_CD_READ   cdReadHeader = NULL;
2407*3088717bSVictor Perevertkin         ULONG                   additionalLength = sizeof(FEATURE_DATA_CD_READ) - sizeof(FEATURE_HEADER);
2408*3088717bSVictor Perevertkin 
2409*3088717bSVictor Perevertkin         cdReadHeader = DeviceFindFeaturePage(DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBuffer,
2410*3088717bSVictor Perevertkin                                             DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBufferSize,
2411*3088717bSVictor Perevertkin                                             FeatureCdRead);
2412*3088717bSVictor Perevertkin 
2413*3088717bSVictor Perevertkin         if ((cdReadHeader != NULL) &&
2414*3088717bSVictor Perevertkin             (cdReadHeader->Header.AdditionalLength >= additionalLength) &&
2415*3088717bSVictor Perevertkin             (cdReadHeader->C2ErrorData)
2416*3088717bSVictor Perevertkin             )
2417*3088717bSVictor Perevertkin         {
2418*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2419*3088717bSVictor Perevertkin                       "DeviceSetRawReadInfo: FDO %p GET_CONFIG shows ability to read C2 error bits\n",
2420*3088717bSVictor Perevertkin                       DeviceExtension->DeviceObject
2421*3088717bSVictor Perevertkin                       ));
2422*3088717bSVictor Perevertkin             DeviceExtension->DeviceAdditionalData.Mmc.ReadCdC2Pointers = TRUE;    // Device returns C2 error info.
2423*3088717bSVictor Perevertkin         }
2424*3088717bSVictor Perevertkin     }
2425*3088717bSVictor Perevertkin 
2426*3088717bSVictor Perevertkin     // Unfortunately, the only way to check for the ability to read R-W subcode
2427*3088717bSVictor Perevertkin     // information is via MODE_SENSE.  Do so here, and check the C2 bit as well
2428*3088717bSVictor Perevertkin     // in case the drive has a firmware bug where it fails to report this ability
2429*3088717bSVictor Perevertkin     // in GET_CONFIG (which some drives do).
2430*3088717bSVictor Perevertkin     for (count = 0; count < 6; count++)
2431*3088717bSVictor Perevertkin     {
2432*3088717bSVictor Perevertkin         SCSI_REQUEST_BLOCK  srb = {0};
2433*3088717bSVictor Perevertkin         PCDB                cdb = (PCDB)srb.Cdb;
2434*3088717bSVictor Perevertkin         ULONG               bufferLength = 0;
2435*3088717bSVictor Perevertkin 
2436*3088717bSVictor Perevertkin         // Build the MODE SENSE CDB.  Try 10-byte CDB first.
2437*3088717bSVictor Perevertkin         if ((count/3) == 0)
2438*3088717bSVictor Perevertkin         {
2439*3088717bSVictor Perevertkin             bufferLength = sizeof(CDVD_CAPABILITIES_PAGE)  +
2440*3088717bSVictor Perevertkin                            sizeof(MODE_PARAMETER_HEADER10) +
2441*3088717bSVictor Perevertkin                            sizeof(MODE_PARAMETER_BLOCK);
2442*3088717bSVictor Perevertkin 
2443*3088717bSVictor Perevertkin             cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
2444*3088717bSVictor Perevertkin             cdb->MODE_SENSE10.Dbd = 1;
2445*3088717bSVictor Perevertkin             cdb->MODE_SENSE10.PageCode = MODE_PAGE_CAPABILITIES;
2446*3088717bSVictor Perevertkin             cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(bufferLength >> 8);
2447*3088717bSVictor Perevertkin             cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(bufferLength >> 0);
2448*3088717bSVictor Perevertkin             srb.CdbLength = 10;
2449*3088717bSVictor Perevertkin         }
2450*3088717bSVictor Perevertkin         else
2451*3088717bSVictor Perevertkin         {
2452*3088717bSVictor Perevertkin             bufferLength = sizeof(CDVD_CAPABILITIES_PAGE) +
2453*3088717bSVictor Perevertkin                            sizeof(MODE_PARAMETER_HEADER)  +
2454*3088717bSVictor Perevertkin                            sizeof(MODE_PARAMETER_BLOCK);
2455*3088717bSVictor Perevertkin 
2456*3088717bSVictor Perevertkin             cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
2457*3088717bSVictor Perevertkin             cdb->MODE_SENSE.Dbd = 1;
2458*3088717bSVictor Perevertkin             cdb->MODE_SENSE.PageCode = MODE_PAGE_CAPABILITIES;
2459*3088717bSVictor Perevertkin             cdb->MODE_SENSE.AllocationLength = (UCHAR)bufferLength;
2460*3088717bSVictor Perevertkin             srb.CdbLength = 6;
2461*3088717bSVictor Perevertkin         }
2462*3088717bSVictor Perevertkin 
2463*3088717bSVictor Perevertkin         // Set timeout value from device extension.
2464*3088717bSVictor Perevertkin         srb.TimeOutValue = DeviceExtension->TimeOutValue;
2465*3088717bSVictor Perevertkin 
2466*3088717bSVictor Perevertkin         buffer = ExAllocatePoolWithTag(NonPagedPoolNx, bufferLength, CDROM_TAG_MODE_DATA);
2467*3088717bSVictor Perevertkin 
2468*3088717bSVictor Perevertkin         if (buffer == NULL)
2469*3088717bSVictor Perevertkin         {
2470*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL,
2471*3088717bSVictor Perevertkin                       "DeviceSetRawReadInfo: cannot allocate "
2472*3088717bSVictor Perevertkin                       "buffer, so not setting raw read info for FDO %p\n",
2473*3088717bSVictor Perevertkin                       DeviceExtension->DeviceObject
2474*3088717bSVictor Perevertkin                       ));
2475*3088717bSVictor Perevertkin             status = STATUS_INSUFFICIENT_RESOURCES;
2476*3088717bSVictor Perevertkin             goto FnExit;
2477*3088717bSVictor Perevertkin         }
2478*3088717bSVictor Perevertkin 
2479*3088717bSVictor Perevertkin         RtlZeroMemory(buffer, bufferLength);
2480*3088717bSVictor Perevertkin 
2481*3088717bSVictor Perevertkin         status = DeviceSendSrbSynchronously(DeviceExtension->Device,
2482*3088717bSVictor Perevertkin                                             &srb,
2483*3088717bSVictor Perevertkin                                             buffer,
2484*3088717bSVictor Perevertkin                                             bufferLength,
2485*3088717bSVictor Perevertkin                                             FALSE,
2486*3088717bSVictor Perevertkin                                             NULL);
2487*3088717bSVictor Perevertkin 
2488*3088717bSVictor Perevertkin         if (NT_SUCCESS(status) ||
2489*3088717bSVictor Perevertkin             (status == STATUS_DATA_OVERRUN) ||
2490*3088717bSVictor Perevertkin             (status == STATUS_BUFFER_OVERFLOW))
2491*3088717bSVictor Perevertkin         {
2492*3088717bSVictor Perevertkin             PCDVD_CAPABILITIES_PAGE capabilities = NULL;
2493*3088717bSVictor Perevertkin 
2494*3088717bSVictor Perevertkin             // determine where the capabilities page really is
2495*3088717bSVictor Perevertkin             if ((count/3) == 0)
2496*3088717bSVictor Perevertkin             {
2497*3088717bSVictor Perevertkin                 PMODE_PARAMETER_HEADER10 p = (PMODE_PARAMETER_HEADER10)buffer;
2498*3088717bSVictor Perevertkin                 capabilities = (PCDVD_CAPABILITIES_PAGE)(buffer +
2499*3088717bSVictor Perevertkin                                                          sizeof(MODE_PARAMETER_HEADER10) +
2500*3088717bSVictor Perevertkin                                                          (p->BlockDescriptorLength[0] * 256) +
2501*3088717bSVictor Perevertkin                                                          p->BlockDescriptorLength[1]);
2502*3088717bSVictor Perevertkin             }
2503*3088717bSVictor Perevertkin             else
2504*3088717bSVictor Perevertkin             {
2505*3088717bSVictor Perevertkin                 PMODE_PARAMETER_HEADER p = (PMODE_PARAMETER_HEADER)buffer;
2506*3088717bSVictor Perevertkin                 capabilities = (PCDVD_CAPABILITIES_PAGE)(buffer +
2507*3088717bSVictor Perevertkin                                                          sizeof(MODE_PARAMETER_HEADER) +
2508*3088717bSVictor Perevertkin                                                          p->BlockDescriptorLength);
2509*3088717bSVictor Perevertkin             }
2510*3088717bSVictor Perevertkin 
2511*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2512*3088717bSVictor Perevertkin                       "DeviceSetRawReadInfo: FDO %p CDVD Capabilities buffer %p\n",
2513*3088717bSVictor Perevertkin                       DeviceExtension->DeviceObject,
2514*3088717bSVictor Perevertkin                       buffer
2515*3088717bSVictor Perevertkin                       ));
2516*3088717bSVictor Perevertkin 
2517*3088717bSVictor Perevertkin             if (capabilities->PageCode == MODE_PAGE_CAPABILITIES)
2518*3088717bSVictor Perevertkin             {
2519*3088717bSVictor Perevertkin                 if (capabilities->C2Pointers)
2520*3088717bSVictor Perevertkin                 {
2521*3088717bSVictor Perevertkin                     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2522*3088717bSVictor Perevertkin                               "DeviceSetRawReadInfo: FDO %p supports C2 error bits in READ_CD command\n",
2523*3088717bSVictor Perevertkin                               DeviceExtension->DeviceObject
2524*3088717bSVictor Perevertkin                               ));
2525*3088717bSVictor Perevertkin                     DeviceExtension->DeviceAdditionalData.Mmc.ReadCdC2Pointers = TRUE;
2526*3088717bSVictor Perevertkin                 }
2527*3088717bSVictor Perevertkin 
2528*3088717bSVictor Perevertkin                 if (capabilities->RWSupported)
2529*3088717bSVictor Perevertkin                 {
2530*3088717bSVictor Perevertkin                     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2531*3088717bSVictor Perevertkin                               "DeviceSetRawReadInfo: FDO %p supports raw subcode in READ_CD command\n",
2532*3088717bSVictor Perevertkin                               DeviceExtension->DeviceObject
2533*3088717bSVictor Perevertkin                               ));
2534*3088717bSVictor Perevertkin                     DeviceExtension->DeviceAdditionalData.Mmc.ReadCdSubCode = TRUE;
2535*3088717bSVictor Perevertkin                 }
2536*3088717bSVictor Perevertkin 
2537*3088717bSVictor Perevertkin                 break;
2538*3088717bSVictor Perevertkin             }
2539*3088717bSVictor Perevertkin         }
2540*3088717bSVictor Perevertkin 
2541*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
2542*3088717bSVictor Perevertkin                   "DeviceSetRawReadInfo: FDO %p failed %x byte mode sense, status %x\n",
2543*3088717bSVictor Perevertkin                   DeviceExtension->DeviceObject,
2544*3088717bSVictor Perevertkin                   (((count/3) == 0) ? 10 : 6),
2545*3088717bSVictor Perevertkin                   status
2546*3088717bSVictor Perevertkin                   ));
2547*3088717bSVictor Perevertkin 
2548*3088717bSVictor Perevertkin         FREE_POOL(buffer);
2549*3088717bSVictor Perevertkin     }
2550*3088717bSVictor Perevertkin 
2551*3088717bSVictor Perevertkin     if (count == 6)
2552*3088717bSVictor Perevertkin     {
2553*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
2554*3088717bSVictor Perevertkin                   "DeviceSetRawReadInfo: FDO %p couldn't get mode sense data\n",
2555*3088717bSVictor Perevertkin                   DeviceExtension->DeviceObject
2556*3088717bSVictor Perevertkin                   ));
2557*3088717bSVictor Perevertkin     }
2558*3088717bSVictor Perevertkin 
2559*3088717bSVictor Perevertkin FnExit:
2560*3088717bSVictor Perevertkin 
2561*3088717bSVictor Perevertkin     if (buffer)
2562*3088717bSVictor Perevertkin     {
2563*3088717bSVictor Perevertkin         FREE_POOL(buffer);
2564*3088717bSVictor Perevertkin     }
2565*3088717bSVictor Perevertkin 
2566*3088717bSVictor Perevertkin     return status;
2567*3088717bSVictor Perevertkin }
2568*3088717bSVictor Perevertkin 
2569*3088717bSVictor Perevertkin 
_IRQL_requires_max_(APC_LEVEL)2570*3088717bSVictor Perevertkin _IRQL_requires_max_(APC_LEVEL)
2571*3088717bSVictor Perevertkin NTSTATUS
2572*3088717bSVictor Perevertkin DeviceInitializeDvd(
2573*3088717bSVictor Perevertkin     _In_ WDFDEVICE Device
2574*3088717bSVictor Perevertkin     )
2575*3088717bSVictor Perevertkin /*++
2576*3088717bSVictor Perevertkin 
2577*3088717bSVictor Perevertkin Routine Description:
2578*3088717bSVictor Perevertkin 
2579*3088717bSVictor Perevertkin     This routine sets the region of DVD drive
2580*3088717bSVictor Perevertkin     NOTE: this routine uses ScratchBuffer, it must be called after ScratchBuffer allocated.
2581*3088717bSVictor Perevertkin 
2582*3088717bSVictor Perevertkin Arguments:
2583*3088717bSVictor Perevertkin 
2584*3088717bSVictor Perevertkin     Device - device object
2585*3088717bSVictor Perevertkin 
2586*3088717bSVictor Perevertkin Return Value:
2587*3088717bSVictor Perevertkin 
2588*3088717bSVictor Perevertkin     NTSTATUS
2589*3088717bSVictor Perevertkin 
2590*3088717bSVictor Perevertkin --*/
2591*3088717bSVictor Perevertkin 
2592*3088717bSVictor Perevertkin {
2593*3088717bSVictor Perevertkin     NTSTATUS                    status = STATUS_SUCCESS;
2594*3088717bSVictor Perevertkin     PCDROM_DEVICE_EXTENSION     deviceExtension;
2595*3088717bSVictor Perevertkin     PDVD_COPY_PROTECT_KEY       copyProtectKey = NULL;
2596*3088717bSVictor Perevertkin     PDVD_RPC_KEY                rpcKey = NULL;
2597*3088717bSVictor Perevertkin     ULONG                       bufferLen = 0;
2598*3088717bSVictor Perevertkin     size_t                      bytesReturned;
2599*3088717bSVictor Perevertkin 
2600*3088717bSVictor Perevertkin     PAGED_CODE();
2601*3088717bSVictor Perevertkin 
2602*3088717bSVictor Perevertkin     deviceExtension = DeviceGetExtension(Device);
2603*3088717bSVictor Perevertkin 
2604*3088717bSVictor Perevertkin     // check to see if we have a DVD device
2605*3088717bSVictor Perevertkin     if (deviceExtension->DeviceAdditionalData.DriveDeviceType != FILE_DEVICE_DVD)
2606*3088717bSVictor Perevertkin     {
2607*3088717bSVictor Perevertkin         return STATUS_SUCCESS;
2608*3088717bSVictor Perevertkin     }
2609*3088717bSVictor Perevertkin 
2610*3088717bSVictor Perevertkin     // we got a DVD drive.
2611*3088717bSVictor Perevertkin     bufferLen = DVD_RPC_KEY_LENGTH;
2612*3088717bSVictor Perevertkin     copyProtectKey = (PDVD_COPY_PROTECT_KEY)ExAllocatePoolWithTag(PagedPool,
2613*3088717bSVictor Perevertkin                                                                   bufferLen,
2614*3088717bSVictor Perevertkin                                                                   DVD_TAG_RPC2_CHECK);
2615*3088717bSVictor Perevertkin 
2616*3088717bSVictor Perevertkin     if (copyProtectKey == NULL)
2617*3088717bSVictor Perevertkin     {
2618*3088717bSVictor Perevertkin         return STATUS_INSUFFICIENT_RESOURCES;
2619*3088717bSVictor Perevertkin     }
2620*3088717bSVictor Perevertkin 
2621*3088717bSVictor Perevertkin     // get the device region
2622*3088717bSVictor Perevertkin     RtlZeroMemory (copyProtectKey, bufferLen);
2623*3088717bSVictor Perevertkin     copyProtectKey->KeyLength = DVD_RPC_KEY_LENGTH;
2624*3088717bSVictor Perevertkin     copyProtectKey->KeyType = DvdGetRpcKey;
2625*3088717bSVictor Perevertkin 
2626*3088717bSVictor Perevertkin     // perform IOCTL_DVD_READ_KEY
2627*3088717bSVictor Perevertkin     status = DvdStartSessionReadKey(deviceExtension,
2628*3088717bSVictor Perevertkin                                     IOCTL_DVD_READ_KEY,
2629*3088717bSVictor Perevertkin                                     NULL,
2630*3088717bSVictor Perevertkin                                     copyProtectKey,
2631*3088717bSVictor Perevertkin                                     DVD_RPC_KEY_LENGTH,
2632*3088717bSVictor Perevertkin                                     copyProtectKey,
2633*3088717bSVictor Perevertkin                                     DVD_RPC_KEY_LENGTH,
2634*3088717bSVictor Perevertkin                                     &bytesReturned);
2635*3088717bSVictor Perevertkin 
2636*3088717bSVictor Perevertkin     if (NT_SUCCESS(status))
2637*3088717bSVictor Perevertkin     {
2638*3088717bSVictor Perevertkin         rpcKey = (PDVD_RPC_KEY)copyProtectKey->KeyData;
2639*3088717bSVictor Perevertkin 
2640*3088717bSVictor Perevertkin         // TypeCode of zero means that no region has been set.
2641*3088717bSVictor Perevertkin         if (rpcKey->TypeCode == 0)
2642*3088717bSVictor Perevertkin         {
2643*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP,
2644*3088717bSVictor Perevertkin                         "DVD Initialize (%p): must choose DVD region\n",
2645*3088717bSVictor Perevertkin                         Device));
2646*3088717bSVictor Perevertkin             deviceExtension->DeviceAdditionalData.PickDvdRegion = 1;
2647*3088717bSVictor Perevertkin 
2648*3088717bSVictor Perevertkin             // set the device region code to be the same as region code on media.
2649*3088717bSVictor Perevertkin             if (deviceExtension->DeviceAdditionalData.Mmc.IsCssDvd)
2650*3088717bSVictor Perevertkin             {
2651*3088717bSVictor Perevertkin                 DevicePickDvdRegion(Device);
2652*3088717bSVictor Perevertkin             }
2653*3088717bSVictor Perevertkin         }
2654*3088717bSVictor Perevertkin     }
2655*3088717bSVictor Perevertkin 
2656*3088717bSVictor Perevertkin     FREE_POOL(copyProtectKey);
2657*3088717bSVictor Perevertkin 
2658*3088717bSVictor Perevertkin     // return status of IOCTL_DVD_READ_KEY will be ignored.
2659*3088717bSVictor Perevertkin     return STATUS_SUCCESS;
2660*3088717bSVictor Perevertkin }
2661*3088717bSVictor Perevertkin 
2662*3088717bSVictor Perevertkin 
2663*3088717bSVictor Perevertkin #if (NTDDI_VERSION >= NTDDI_WIN8)
_IRQL_requires_max_(PASSIVE_LEVEL)2664*3088717bSVictor Perevertkin _IRQL_requires_max_(PASSIVE_LEVEL)
2665*3088717bSVictor Perevertkin NTSTATUS
2666*3088717bSVictor Perevertkin DeviceIsPortable(
2667*3088717bSVictor Perevertkin     _In_  PCDROM_DEVICE_EXTENSION   DeviceExtension,
2668*3088717bSVictor Perevertkin     _Out_ PBOOLEAN                  IsPortable
2669*3088717bSVictor Perevertkin     )
2670*3088717bSVictor Perevertkin /*++
2671*3088717bSVictor Perevertkin 
2672*3088717bSVictor Perevertkin Routine Description:
2673*3088717bSVictor Perevertkin 
2674*3088717bSVictor Perevertkin     This routine checks if the volume is on a portable storage device.
2675*3088717bSVictor Perevertkin 
2676*3088717bSVictor Perevertkin Arguments:
2677*3088717bSVictor Perevertkin 
2678*3088717bSVictor Perevertkin     DeviceExtension - device context
2679*3088717bSVictor Perevertkin     IsPortable - device is portable
2680*3088717bSVictor Perevertkin 
2681*3088717bSVictor Perevertkin Return Value:
2682*3088717bSVictor Perevertkin 
2683*3088717bSVictor Perevertkin     NTSTATUS.
2684*3088717bSVictor Perevertkin 
2685*3088717bSVictor Perevertkin --*/
2686*3088717bSVictor Perevertkin 
2687*3088717bSVictor Perevertkin {
2688*3088717bSVictor Perevertkin     DEVPROP_BOOLEAN isInternal = DEVPROP_FALSE;
2689*3088717bSVictor Perevertkin     BOOLEAN         isPortable = FALSE;
2690*3088717bSVictor Perevertkin     ULONG           size       = 0;
2691*3088717bSVictor Perevertkin     NTSTATUS        status     = STATUS_SUCCESS;
2692*3088717bSVictor Perevertkin     DEVPROPTYPE     type       = DEVPROP_TYPE_EMPTY;
2693*3088717bSVictor Perevertkin 
2694*3088717bSVictor Perevertkin     PAGED_CODE();
2695*3088717bSVictor Perevertkin 
2696*3088717bSVictor Perevertkin     *IsPortable = FALSE;
2697*3088717bSVictor Perevertkin 
2698*3088717bSVictor Perevertkin     // Check to see if the underlying device object is in local machine container
2699*3088717bSVictor Perevertkin     status = IoGetDevicePropertyData(DeviceExtension->LowerPdo,
2700*3088717bSVictor Perevertkin                                      &DEVPKEY_Device_InLocalMachineContainer,
2701*3088717bSVictor Perevertkin                                      0,
2702*3088717bSVictor Perevertkin                                      0,
2703*3088717bSVictor Perevertkin                                      sizeof(isInternal),
2704*3088717bSVictor Perevertkin                                      &isInternal,
2705*3088717bSVictor Perevertkin                                      &size,
2706*3088717bSVictor Perevertkin                                      &type);
2707*3088717bSVictor Perevertkin 
2708*3088717bSVictor Perevertkin     if (!NT_SUCCESS(status))
2709*3088717bSVictor Perevertkin     {
2710*3088717bSVictor Perevertkin         goto Cleanup;
2711*3088717bSVictor Perevertkin     }
2712*3088717bSVictor Perevertkin 
2713*3088717bSVictor Perevertkin     NT_ASSERT(size == sizeof(isInternal));
2714*3088717bSVictor Perevertkin     NT_ASSERT(type == DEVPROP_TYPE_BOOLEAN);
2715*3088717bSVictor Perevertkin 
2716*3088717bSVictor Perevertkin     // Volume is hot-pluggable if the disk pdo container id differs from that of root device
2717*3088717bSVictor Perevertkin     if (isInternal == DEVPROP_TRUE)
2718*3088717bSVictor Perevertkin     {
2719*3088717bSVictor Perevertkin         goto Cleanup;
2720*3088717bSVictor Perevertkin     }
2721*3088717bSVictor Perevertkin 
2722*3088717bSVictor Perevertkin     isPortable = TRUE;
2723*3088717bSVictor Perevertkin 
2724*3088717bSVictor Perevertkin     // Examine the bus type to  ensure that this really is a fixed device
2725*3088717bSVictor Perevertkin     if (DeviceExtension->DeviceDescriptor->BusType == BusTypeFibre ||
2726*3088717bSVictor Perevertkin         DeviceExtension->DeviceDescriptor->BusType == BusTypeiScsi ||
2727*3088717bSVictor Perevertkin         DeviceExtension->DeviceDescriptor->BusType == BusTypeRAID)
2728*3088717bSVictor Perevertkin     {
2729*3088717bSVictor Perevertkin         isPortable = FALSE;
2730*3088717bSVictor Perevertkin     }
2731*3088717bSVictor Perevertkin 
2732*3088717bSVictor Perevertkin     *IsPortable = isPortable;
2733*3088717bSVictor Perevertkin 
2734*3088717bSVictor Perevertkin Cleanup:
2735*3088717bSVictor Perevertkin 
2736*3088717bSVictor Perevertkin     return status;
2737*3088717bSVictor Perevertkin }
2738*3088717bSVictor Perevertkin #endif
2739*3088717bSVictor Perevertkin 
2740*3088717bSVictor Perevertkin 
2741*3088717bSVictor Perevertkin #pragma warning(pop) // un-sets any local warning changes
2742*3088717bSVictor Perevertkin 
2743