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 ®istryKey);
1684*3088717bSVictor Perevertkin
1685*3088717bSVictor Perevertkin if (NT_SUCCESS(status))
1686*3088717bSVictor Perevertkin {
1687*3088717bSVictor Perevertkin status = WdfRegistryQueryULong(registryKey,
1688*3088717bSVictor Perevertkin ®istryValueName,
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