1 /*++
2
3 Copyright (c) Microsoft Corporation
4
5 Module Name:
6
7 FxDmaEnablerAPI.cpp
8
9 Abstract:
10
11 Base for WDF DMA Enabler object APIs
12
13 Environment:
14
15 Kernel mode only.
16
17 Notes:
18
19
20 Revision History:
21
22 --*/
23
24 #include "fxdmapch.hpp"
25
26 extern "C" {
27 // #include "FxDmaEnablerAPI.tmh"
28 }
29
30 //
31 // Extern "C" the entire file
32 //
33 extern "C" {
34
35 _Must_inspect_result_
__drv_maxIRQL(PASSIVE_LEVEL)36 __drv_maxIRQL(PASSIVE_LEVEL)
37 NTSTATUS
38 WDFEXPORT(WdfDmaEnablerCreate)(
39 __in
40 PWDF_DRIVER_GLOBALS DriverGlobals,
41 __in
42 WDFDEVICE Device,
43 __in
44 WDF_DMA_ENABLER_CONFIG * Config,
45 __in_opt
46 WDF_OBJECT_ATTRIBUTES * Attributes,
47 __out
48 WDFDMAENABLER * DmaEnablerHandle
49 )
50 {
51 FxDmaEnabler * pDmaEnabler;
52 FxDeviceBase * pDevice;
53 NTSTATUS status;
54 WDFDMAENABLER handle;
55 PFX_DRIVER_GLOBALS pFxDriverGlobals;
56 FxObject * pParent;
57 WDF_DMA_ENABLER_CONFIG dmaConfig;
58
59 //
60 // Validate the Device handle
61 //
62 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
63 Device,
64 FX_TYPE_DEVICE_BASE,
65 (PVOID *) &pDevice,
66 &pFxDriverGlobals);
67
68 status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
69 if (!NT_SUCCESS(status)) {
70 return status;
71 }
72
73 FxPointerNotNull(pFxDriverGlobals, DmaEnablerHandle);
74 FxPointerNotNull(pFxDriverGlobals, Config);
75
76 *DmaEnablerHandle = NULL;
77
78 status = FxValidateObjectAttributes(pFxDriverGlobals, Attributes);
79
80 if (!NT_SUCCESS(status)) {
81 return status;
82 }
83
84 if (Attributes != NULL && Attributes->ParentObject != NULL) {
85 FxObjectHandleGetPtr(pFxDriverGlobals,
86 Attributes->ParentObject,
87 FX_TYPE_OBJECT,
88 (PVOID*)&pParent);
89
90 if (pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,11)) {
91 FxDeviceBase * pSearchDevice;
92
93 //
94 // If a parent object is passed-in it must be descendent of device.
95 // DmaEnabler stores device and uses it during dispose
96 // (to remove it from dmaenabler list maintained at device level),
97 // so DmaEnabler cannot outlive device.
98 //
99
100 pSearchDevice = FxDeviceBase::_SearchForDevice(pParent, NULL);
101
102 if (pSearchDevice == NULL) {
103 status = STATUS_WDF_OBJECT_ATTRIBUTES_INVALID;
104
105 DoTraceLevelMessage(
106 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
107 "Attributes->ParentObject 0x%p must have WDFDEVICE as an "
108 "eventual ancestor, %!STATUS!",
109 Attributes->ParentObject, status);
110
111 return status;
112 }
113 else if (pSearchDevice != pDevice) {
114 status = STATUS_WDF_OBJECT_ATTRIBUTES_INVALID;
115
116 DoTraceLevelMessage(
117 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
118 "Attributes->ParentObject 0x%p ancestor is WDFDEVICE %p, but "
119 "not the same WDFDEVICE 0x%p passed to WdfDmaEnablerCreate, "
120 "%!STATUS!",
121 Attributes->ParentObject, pSearchDevice->GetHandle(),
122 Device, status);
123
124 return status;
125 }
126 }
127 else {
128 //
129 // For < 1.11 drivers we only allow pDevice to be the parent
130 // since that is what we were blindly setting the parent to.
131 //
132 // Using the passed-in parent for such drivers could cause
133 // side-effects such as earlier deletion of DmaEnabler object. So
134 // we don't do that.
135 //
136 // We cause this verifier breakpoint to warn downlevel drivers
137 // that the parent they passed in gets ignored.
138 //
139 if (pParent != pDevice) {
140 DoTraceLevelMessage(
141 pFxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGDMA,
142 "For drivers bound to version <= 1.9 "
143 "WdfDmaEnablerCreate uses WDFDEVICE as the "
144 "parent object for the dma enabler object. "
145 "Attributes->ParentObject 0x%p, which is different from "
146 "WDFDEVICE 0x%p, gets ignored. Please note that DmaEnabler "
147 "would be disposed only when device is disposed.",
148 Attributes->ParentObject, Device);
149
150 if (pFxDriverGlobals->IsDownlevelVerificationEnabled()) {
151 FxVerifierDbgBreakPoint(pFxDriverGlobals);
152 }
153 }
154
155 pParent = pDevice;
156 }
157 }
158 else {
159 pParent = pDevice;
160 }
161
162 {
163 ULONG expectedSize = pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,11) ?
164 sizeof(WDF_DMA_ENABLER_CONFIG) :
165 sizeof(WDF_DMA_ENABLER_CONFIG_V1_9);
166
167 if (Config->Size != expectedSize) {
168 status = STATUS_INFO_LENGTH_MISMATCH;
169
170 DoTraceLevelMessage(
171 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
172 "WDF_DMA_ENABLER_CONFIG Size 0x%x, expected 0x%x, %!STATUS!",
173 Config->Size, expectedSize, status);
174
175 return status;
176 }
177
178
179 //
180 // Normalize DMA config structure if necessary.
181 //
182 if (Config->Size < sizeof(WDF_DMA_ENABLER_CONFIG)) {
183 //
184 // Init new fields to default values.
185 //
186 WDF_DMA_ENABLER_CONFIG_INIT(&dmaConfig,
187 Config->Profile,
188 Config->MaximumLength);
189 //
190 // Copy over existing fields and readjust the struct size.
191 //
192 RtlCopyMemory(&dmaConfig, Config, Config->Size);
193 dmaConfig.Size = sizeof(dmaConfig);
194
195 //
196 // Use new config structure from now on.
197 //
198 Config = &dmaConfig;
199 }
200 }
201
202 switch (Config->Profile) {
203 case WdfDmaProfilePacket:
204 case WdfDmaProfileScatterGather:
205 case WdfDmaProfilePacket64:
206 case WdfDmaProfileScatterGather64:
207 case WdfDmaProfileScatterGather64Duplex:
208 case WdfDmaProfileScatterGatherDuplex:
209 case WdfDmaProfileSystem:
210 case WdfDmaProfileSystemDuplex:
211 break;
212 default:
213 status = STATUS_INVALID_PARAMETER;
214 DoTraceLevelMessage(
215 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
216 "DMA Profile value %d is unknown, %!STATUS!",
217 Config->Profile, status);
218 return status;
219 }
220
221 if (Config->MaximumLength == 0) {
222 status = STATUS_INVALID_PARAMETER;
223
224 DoTraceLevelMessage(
225 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
226 "Config MaximumLength of zero is invalid, %!STATUS!",
227 status);
228
229 return status;
230 }
231
232 //
233 // Ok: create a new DmaEnabler
234 //
235 pDmaEnabler = new(pFxDriverGlobals, Attributes)
236 FxDmaEnabler( pFxDriverGlobals );
237
238 if (pDmaEnabler == NULL) {
239 status = STATUS_INSUFFICIENT_RESOURCES;
240
241 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
242 "Could not allocate memory for a WDFDMAENABLER, "
243 "%!STATUS!", status);
244
245 return status;
246 }
247
248 //
249 // Assign this FxDmaEnabler to its parent FxDevice object.
250 //
251 status = pDmaEnabler->Commit(Attributes, (WDFOBJECT*)&handle, pParent);
252
253 if (NT_SUCCESS(status)) {
254 //
255 // Ok: start this DmaEnabler.
256 //
257 status = pDmaEnabler->Initialize( Config, pDevice );
258 }
259
260 if (NT_SUCCESS(status)) {
261 //
262 // Only return a valid handle on success.
263 //
264 *DmaEnablerHandle = handle;
265 }
266 else {
267 pDmaEnabler->DeleteFromFailedCreate();
268 }
269
270 return status;
271 }
272
__drv_maxIRQL(DISPATCH_LEVEL)273 __drv_maxIRQL(DISPATCH_LEVEL)
274 size_t
275 WDFEXPORT(WdfDmaEnablerGetMaximumLength)(
276 __in
277 PWDF_DRIVER_GLOBALS DriverGlobals,
278 __in
279 WDFDMAENABLER DmaEnabler
280 )
281 {
282 FxDmaEnabler * pDmaEnabler;
283
284 FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
285 DmaEnabler,
286 FX_TYPE_DMA_ENABLER,
287 (PVOID *) &pDmaEnabler);
288
289 return pDmaEnabler->GetMaximumLength();
290 }
291
__drv_maxIRQL(DISPATCH_LEVEL)292 __drv_maxIRQL(DISPATCH_LEVEL)
293 size_t
294 WDFEXPORT(WdfDmaEnablerGetMaximumScatterGatherElements)(
295 __in
296 PWDF_DRIVER_GLOBALS DriverGlobals,
297 __in
298 WDFDMAENABLER DmaEnabler
299 )
300 {
301 FxDmaEnabler * pDmaEnabler;
302
303 FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
304 DmaEnabler,
305 FX_TYPE_DMA_ENABLER,
306 (PVOID *) &pDmaEnabler);
307
308 return pDmaEnabler->GetMaxSGElements();
309 }
310
311
__drv_maxIRQL(PASSIVE_LEVEL)312 __drv_maxIRQL(PASSIVE_LEVEL)
313 VOID
314 WDFEXPORT(WdfDmaEnablerSetMaximumScatterGatherElements)(
315 __in
316 PWDF_DRIVER_GLOBALS DriverGlobals,
317 __in
318 WDFDMAENABLER DmaEnabler,
319 __in
320 __drv_when(MaximumElements == 0, __drv_reportError(MaximumElements cannot be zero))
321 size_t MaximumElements
322 )
323 {
324 PFX_DRIVER_GLOBALS pFxDriverGlobals;
325 FxDmaEnabler * pDmaEnabler;
326 NTSTATUS status;
327
328 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
329 DmaEnabler,
330 FX_TYPE_DMA_ENABLER,
331 (PVOID *) &pDmaEnabler,
332 &pFxDriverGlobals);
333
334 status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
335 if (!NT_SUCCESS(status)) {
336 return;
337 }
338
339 if (MaximumElements == 0) {
340 DoTraceLevelMessage(
341 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
342 "Cannot set MaximumElements of zero on WDFDMAENABLER %p",
343 DmaEnabler);
344 return;
345 }
346
347 pDmaEnabler->SetMaxSGElements(MaximumElements);
348 }
349
__drv_maxIRQL(DISPATCH_LEVEL)350 __drv_maxIRQL(DISPATCH_LEVEL)
351 size_t
352 WDFEXPORT(WdfDmaEnablerGetFragmentLength)(
353 __in
354 PWDF_DRIVER_GLOBALS DriverGlobals,
355 __in
356 WDFDMAENABLER DmaEnabler,
357 __in
358 WDF_DMA_DIRECTION DmaDirection
359 )
360 {
361 FxDmaEnabler * pDmaEnabler;
362 size_t length;
363 PFX_DRIVER_GLOBALS pFxDriverGlobals;
364
365 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
366 DmaEnabler,
367 FX_TYPE_DMA_ENABLER,
368 (PVOID *) &pDmaEnabler,
369 &pFxDriverGlobals);
370
371 switch (DmaDirection) {
372
373 case WdfDmaDirectionReadFromDevice:
374 length = pDmaEnabler->GetReadDmaDescription()->MaximumFragmentLength;
375 break;
376
377 case WdfDmaDirectionWriteToDevice:
378 length = pDmaEnabler->GetWriteDmaDescription()->MaximumFragmentLength;
379 break;
380
381 default:
382 length = 0;
383 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
384 "Invalid value for Dma direction %d, %p",
385 DmaDirection, DmaEnabler);
386 FxVerifierDbgBreakPoint(pFxDriverGlobals);
387 break;
388 }
389
390 return length;
391 }
392
__drv_maxIRQL(DISPATCH_LEVEL)393 __drv_maxIRQL(DISPATCH_LEVEL)
394 PDMA_ADAPTER
395 WDFEXPORT(WdfDmaEnablerWdmGetDmaAdapter)(
396 __in
397 PWDF_DRIVER_GLOBALS DriverGlobals,
398 __in
399 WDFDMAENABLER DmaEnabler,
400 __in
401 WDF_DMA_DIRECTION DmaDirection
402 )
403 {
404 PDMA_ADAPTER adapter;
405 PFX_DRIVER_GLOBALS pFxDriverGlobals;
406 FxDmaEnabler * pDmaEnabler;
407
408 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
409 DmaEnabler,
410 FX_TYPE_DMA_ENABLER,
411 (PVOID *) &pDmaEnabler,
412 &pFxDriverGlobals);
413
414 switch (DmaDirection) {
415
416 case WdfDmaDirectionReadFromDevice:
417 adapter = pDmaEnabler->GetReadDmaDescription()->AdapterObject;
418 break;
419
420 case WdfDmaDirectionWriteToDevice:
421 adapter = pDmaEnabler->GetWriteDmaDescription()->AdapterObject;
422 break;
423
424 default:
425 adapter = NULL;
426 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
427 "Invalid value for Dma direction %d, %p",
428 DmaDirection, DmaEnabler);
429 FxVerifierDbgBreakPoint(pFxDriverGlobals);
430 break;
431 }
432
433 return adapter;
434 }
435
436 _Must_inspect_result_
__drv_maxIRQL(PASSIVE_LEVEL)437 __drv_maxIRQL(PASSIVE_LEVEL)
438 NTSTATUS
439 WDFEXPORT(WdfDmaEnablerConfigureSystemProfile)(
440 __in
441 PWDF_DRIVER_GLOBALS DriverGlobals,
442 __in
443 WDFDMAENABLER DmaEnabler,
444 __in
445 PWDF_DMA_SYSTEM_PROFILE_CONFIG ProfileConfig,
446 __in
447 WDF_DMA_DIRECTION ConfigDirection
448 )
449 {
450 PFX_DRIVER_GLOBALS pFxDriverGlobals;
451 FxDmaEnabler * pDmaEnabler;
452
453 NTSTATUS status;
454
455 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
456 DmaEnabler,
457 FX_TYPE_DMA_ENABLER,
458 (PVOID *) &pDmaEnabler,
459 &pFxDriverGlobals);
460
461 //
462 // Verify the DMA config
463 //
464
465 if (ProfileConfig == NULL)
466 {
467 status = STATUS_INVALID_PARAMETER;
468 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
469 "ProfileConfig must be non-null, %!STATUS!",
470 status);
471 FxVerifierDbgBreakPoint(pFxDriverGlobals);
472 return status;
473 }
474
475 if (ProfileConfig->Size != sizeof(WDF_DMA_SYSTEM_PROFILE_CONFIG))
476 {
477 status = STATUS_INFO_LENGTH_MISMATCH;
478
479 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
480 "WDF_DMA_SYSTEM_PROFILE_CONFIG Size 0x%x, expected 0x%x, %!STATUS!",
481 ProfileConfig->Size, sizeof(WDF_DMA_SYSTEM_PROFILE_CONFIG), status);
482
483 FxVerifierDbgBreakPoint(pFxDriverGlobals);
484
485 return status;
486 }
487
488 if (ProfileConfig->DmaDescriptor == NULL)
489 {
490 status = STATUS_INVALID_PARAMETER;
491
492 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
493 "ProfileConfig (%p) may not have NULL DmaDescriptor, %!STATUS!",
494 ProfileConfig, status);
495
496 FxVerifierDbgBreakPoint(pFxDriverGlobals);
497
498 return status;
499 }
500
501 if (ConfigDirection != WdfDmaDirectionReadFromDevice &&
502 ConfigDirection != WdfDmaDirectionWriteToDevice) {
503 status = STATUS_INVALID_PARAMETER;
504 DoTraceLevelMessage(
505 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
506 "ConfigDirection 0x%x is an invalid value, %!STATUS!",
507 ConfigDirection, status);
508 return status;
509 }
510
511 status = pDmaEnabler->ConfigureSystemAdapter(ProfileConfig,
512 ConfigDirection);
513 return status;
514 }
515
516 } // extern "C"
517