1 /*++
2
3 Copyright (c) Microsoft Corporation
4
5 Module Name:
6
7 FxDeviceBase.cpp
8
9 Abstract:
10
11 This is the class implementation for the base device class.
12
13 Author:
14
15
16
17 Environment:
18
19 Both kernel and user mode
20
21 Revision History:
22
23 --*/
24
25 #include "coreprivshared.hpp"
26
27 extern "C" {
28 // #include "FxDeviceBase.tmh"
29 }
30
FxDeviceBase(__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in FxDriver * Driver,__in WDFTYPE Type,__in USHORT Size)31 FxDeviceBase::FxDeviceBase(
32 __in PFX_DRIVER_GLOBALS FxDriverGlobals,
33 __in FxDriver* Driver,
34 __in WDFTYPE Type,
35 __in USHORT Size
36 ) :
37 FxNonPagedObject(Type, Size, FxDriverGlobals)
38 {
39 m_Driver = Driver;
40
41 m_CallbackLockPtr = NULL;
42 m_CallbackLockObjectPtr = NULL;
43
44 m_DisposeList = NULL;
45
46 m_DmaPacketTransactionStatus = FxDmaPacketTransactionCompleted;
47
48 m_ExecutionLevel = WdfExecutionLevelInheritFromParent;
49 m_SynchronizationScope = WdfSynchronizationScopeInheritFromParent;
50
51 MarkPassiveDispose(ObjectDoNotLock);
52 SetDeviceBase(this);
53 }
54
~FxDeviceBase(VOID)55 FxDeviceBase::~FxDeviceBase(
56 VOID
57 )
58 {
59 if (m_DisposeList != NULL) {
60 m_DisposeList->DeleteObject();
61 m_DisposeList = NULL;
62 }
63
64 if (m_CallbackLockPtr != NULL) {
65 delete m_CallbackLockPtr;
66 m_CallbackLockPtr = NULL;
67 }
68 }
69
70 _Must_inspect_result_
71 NTSTATUS
QueryInterface(__inout FxQueryInterfaceParams * Params)72 FxDeviceBase::QueryInterface(
73 __inout FxQueryInterfaceParams* Params
74 )
75 {
76 switch (Params->Type) {
77 case FX_TYPE_DEVICE_BASE:
78 *Params->Object = this;
79 break;
80
81 case FX_TYPE_IHASCALLBACKS:
82 *Params->Object = (IFxHasCallbacks*) this;
83 break;
84
85 default:
86 return FxNonPagedObject::QueryInterface(Params); // __super call
87 }
88
89 return STATUS_SUCCESS;
90 }
91
92 NTSTATUS
ConfigureConstraints(__in_opt PWDF_OBJECT_ATTRIBUTES ObjectAttributes)93 FxDeviceBase::ConfigureConstraints(
94 __in_opt PWDF_OBJECT_ATTRIBUTES ObjectAttributes
95 )
96 {
97 NTSTATUS status;
98 WDF_EXECUTION_LEVEL driverLevel;
99 WDF_SYNCHRONIZATION_SCOPE driverScope;
100
101 ASSERT(m_Driver != NULL);
102
103 //
104 // If WDF_OBJECT_ATTRIBUTES is specified, these override any
105 // default settings.
106 //
107 if (ObjectAttributes != NULL) {
108 m_ExecutionLevel = ObjectAttributes->ExecutionLevel;
109 m_SynchronizationScope = ObjectAttributes->SynchronizationScope;
110 }
111
112 //
113 // If no WDFDEVICE specific attributes are specified, we
114 // get them from WDFDRIVER, which allows WDFDRIVER to
115 // provide a default for all WDFDEVICE's created.
116 //
117 m_Driver->GetConstraints(&driverLevel, &driverScope);
118
119 if (m_ExecutionLevel == WdfExecutionLevelInheritFromParent) {
120 m_ExecutionLevel = driverLevel;
121 }
122
123 if (m_SynchronizationScope == WdfSynchronizationScopeInheritFromParent) {
124 m_SynchronizationScope = driverScope;
125 }
126
127 //
128 // Configure The Execution Level Constraint
129 //
130 if (m_ExecutionLevel == WdfExecutionLevelPassive) {
131 m_CallbackLockPtr = new(GetDriverGlobals())
132 FxCallbackMutexLock(GetDriverGlobals());
133 //
134 // Currently, all event callbacks from FxDevice into the driver
135 // are from PASSIVE_LEVEL threads, and there is no need to defer
136 // to a system workitem like IoQueue. So we don't allocate and
137 // setup an FxSystemWorkItem here.
138 //
139 // If the FxDevice starts raising events to the device driver
140 // whose thread starts out above PASSIVE_LEVEL, then an FxSystemWorkItem
141 // would need to be allocated when WdfExecutionLevelPassive is specified.
142 //
143 // (FDO and PDO variants of FxDevice may own their own event dispatch
144 // and deferral logic separate from FxDevice.)
145 //
146 }
147 else {
148 m_CallbackLockPtr = new(GetDriverGlobals())
149 FxCallbackSpinLock(GetDriverGlobals());
150 }
151
152 //
153 // Finish initializing the spin/mutex lock.
154 //
155 if (NULL == m_CallbackLockPtr) {
156 status = STATUS_INSUFFICIENT_RESOURCES;
157 DoTraceLevelMessage(
158 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGOBJECT,
159 "WDFDEVICE %p, could not allocate callback lock, %!STATUS!",
160 GetHandle(), status);
161 goto Done;
162 }
163
164 m_CallbackLockPtr->Initialize(this);
165 m_CallbackLockObjectPtr = this;
166
167 status = STATUS_SUCCESS;
168
169 Done:
170 return status;
171 }
172
173 VOID
GetConstraints(__out_opt WDF_EXECUTION_LEVEL * ExecutionLevel,__out_opt WDF_SYNCHRONIZATION_SCOPE * SynchronizationScope)174 FxDeviceBase::GetConstraints(
175 __out_opt WDF_EXECUTION_LEVEL* ExecutionLevel,
176 __out_opt WDF_SYNCHRONIZATION_SCOPE* SynchronizationScope
177 )
178 {
179 if (ExecutionLevel != NULL) {
180 *ExecutionLevel = m_ExecutionLevel;
181 }
182
183 if (SynchronizationScope != NULL) {
184 *SynchronizationScope = m_SynchronizationScope;
185 }
186 }
187
188 FxCallbackLock*
GetCallbackLockPtr(__out_opt FxObject ** LockObject)189 FxDeviceBase::GetCallbackLockPtr(
190 __out_opt FxObject** LockObject
191 )
192 {
193 if (LockObject != NULL) {
194 *LockObject = m_CallbackLockObjectPtr;
195 }
196
197 return m_CallbackLockPtr;
198 }
199
200
201 VOID
Init(__in MdDeviceObject DeviceObject,__in MdDeviceObject AttachedDevice,__in MdDeviceObject PhysicalDevice)202 FxDeviceBase::Init(
203 __in MdDeviceObject DeviceObject,
204 __in MdDeviceObject AttachedDevice,
205 __in MdDeviceObject PhysicalDevice
206 )
207 {
208 m_DeviceObject.SetObject(DeviceObject);
209 m_AttachedDevice.SetObject(AttachedDevice);
210 m_PhysicalDevice.SetObject(PhysicalDevice);
211 }
212
213 FxDeviceBase*
_SearchForDevice(__in FxObject * Object,__out_opt IFxHasCallbacks ** Callbacks)214 FxDeviceBase::_SearchForDevice(
215 __in FxObject* Object,
216 __out_opt IFxHasCallbacks** Callbacks
217 )
218 {
219 FxObject* pParent, *pOrigParent;
220 FxDeviceBase* pDeviceBase;
221 FxQueryInterfaceParams cbParams = { (PVOID*) Callbacks, FX_TYPE_IHASCALLBACKS, 0 };
222 PVOID pTag;
223
224 pDeviceBase = Object->GetDeviceBase();
225 if (pDeviceBase == NULL) {
226 DoTraceLevelMessage(
227 Object->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGOBJECT,
228 "WDFHANDLE %p does not have a WDFDEVICE as an ancestor",
229 Object->GetObjectHandle());
230 return NULL;
231 }
232
233 if (Callbacks == NULL) {
234 //
235 // Caller is not interested in the callbacks interface, just return
236 // now without searching for it.
237 //
238 return pDeviceBase;
239 }
240
241 //
242 // Init out parameter.
243 //
244 *Callbacks = NULL;
245
246 pOrigParent = Object;
247 pTag = pOrigParent;
248
249 //
250 // By adding a reference now, we simulate what GetParentObjectReferenced
251 // does later, thus allowing simple logic on when/how to release the
252 // reference on exit.
253 //
254 Object->ADDREF(pTag);
255
256 do {
257 //
258 // If successful, Callbacks will be != NULL
259 //
260 if (NT_SUCCESS(Object->QueryInterface(&cbParams))) {
261 ASSERT(*Callbacks != NULL);
262 //
263 // Release the reference previously taken by the top of the function
264 // or GetParentObjectReferenced in a previous pass in the loop.
265 //
266 Object->RELEASE(pTag);
267 return pDeviceBase;
268 }
269
270 pParent = Object->GetParentObjectReferenced(pTag);
271
272 //
273 // Release the reference previously taken by the top of the function
274 // or GetParentObjectReferenced in a previous pass in the loop.
275 //
276 Object->RELEASE(pTag);
277
278 Object = pParent;
279 } while (Object != NULL);
280
281 ASSERT(Object == NULL);
282
283 //
284 // Queue presented requests do not have parents (to increase performance).
285 // Try to find the callback interface on this object's device base.
286 //
287 if (NT_SUCCESS(pDeviceBase->QueryInterface(&cbParams))) {
288 ASSERT(*Callbacks != NULL);
289 //
290 // Success, we got a callback interface.
291 //
292 return pDeviceBase;
293 }
294
295 DoTraceLevelMessage(
296 pOrigParent->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGOBJECT,
297 "WDFHANDLE %p does not have a callbacks interface in its object tree"
298 "(WDFDEVICE %p)", pOrigParent->GetObjectHandle(),
299 pDeviceBase->GetHandle());
300
301 return pDeviceBase;
302 }
303
304 FxDeviceBase*
_SearchForDevice(__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in_opt PWDF_OBJECT_ATTRIBUTES Attributes)305 FxDeviceBase::_SearchForDevice(
306 __in PFX_DRIVER_GLOBALS FxDriverGlobals,
307 __in_opt PWDF_OBJECT_ATTRIBUTES Attributes
308 )
309 {
310 FxObject* pParentObject;
311 FxDeviceBase* pDeviceBase;
312
313 if (Attributes == NULL || Attributes->ParentObject == NULL) {
314 return NULL;
315 }
316
317 FxObjectHandleGetPtr(FxDriverGlobals,
318 Attributes->ParentObject,
319 FX_TYPE_OBJECT,
320 (PVOID*) &pParentObject);
321
322 pDeviceBase = _SearchForDevice(pParentObject, NULL);
323
324 return pDeviceBase;
325 }
326
327 _Must_inspect_result_
328 NTSTATUS
AllocateTarget(_Out_ FxIoTarget ** Target,_In_ BOOLEAN SelfTarget)329 FxDeviceBase::AllocateTarget(
330 _Out_ FxIoTarget** Target,
331 _In_ BOOLEAN SelfTarget
332 )
333 /*++
334
335 Routine Description:
336
337 Allocates an IO Target or an Self IO target for the FxDevice.
338
339 Arguments:
340
341 Target - Out - returns the pointer to the allocated IO target.
342
343 SelfTarget - If TRUE allocates an Self IO Target, if FALSE allocates
344 a regular IO target.
345
346 Returns:
347
348 NTSTATUS
349
350 --*/
351 {
352 FxIoTarget* pTarget;
353 NTSTATUS status;
354
355 if (SelfTarget) {
356 pTarget = (FxIoTarget*) new(GetDriverGlobals(), WDF_NO_OBJECT_ATTRIBUTES)
357 FxIoTargetSelf(GetDriverGlobals(), sizeof(FxIoTargetSelf));
358 } else {
359 pTarget = new(GetDriverGlobals(), WDF_NO_OBJECT_ATTRIBUTES)
360 FxIoTarget(GetDriverGlobals(), sizeof(FxIoTarget));
361 }
362
363 if (pTarget == NULL) {
364 status = STATUS_INSUFFICIENT_RESOURCES;
365
366 DoTraceLevelMessage(
367 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE,
368 "WDFDEVICE %p could not allocate a WDFIOTARGET, %!STATUS!",
369 GetHandle(), status);
370
371 goto Done;
372 }
373
374 status = AddIoTarget(pTarget);
375 if (!NT_SUCCESS(status)) {
376 DoTraceLevelMessage(
377 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE,
378 "WDFDEVICE %p failed to initialize (add) a WDFIOTARGET, %!STATUS!",
379 GetHandle(), status);
380
381 goto Done;
382 }
383
384 status = pTarget->Init(this);
385 if (!NT_SUCCESS(status)) {
386 DoTraceLevelMessage(
387 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE,
388 "WDFDEVICE %p failed to initialize a WDFIOTARGET, %!STATUS!",
389 GetHandle(), status);
390
391 goto Done;
392 }
393
394 status = pTarget->Commit(WDF_NO_OBJECT_ATTRIBUTES, NULL, this);
395 if (!NT_SUCCESS(status)) {
396 DoTraceLevelMessage(
397 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE,
398 "WDFDEVICE %p failed to initialize (commit) a WDFIOTARGET, %!STATUS!",
399 GetHandle(), status);
400
401 goto Done;
402 }
403
404 status = STATUS_SUCCESS;
405
406 Done:
407 if (!NT_SUCCESS(status)) {
408 if (pTarget != NULL) {
409 pTarget->DeleteFromFailedCreate();
410 pTarget = NULL;
411 }
412 }
413
414 *Target = pTarget;
415
416 return status;
417 }
418