1 /*++
2 
3 Copyright (c) Microsoft Corporation.  All rights reserved.
4 
5 Module Name:
6 
7     FxIoTarget.hpp
8 
9 Abstract:
10 
11     Encapsulation of the target to which FxRequest are sent to.  For example,
12     an FxTarget could represent the next device object in the pnp stack.
13     Derivations from this class could include bus specific formatters or device
14     objects outside of the pnp stack of the device.
15 
16 Author:
17 
18 
19 
20 Environment:
21 
22     Kernel mode only
23 
24 Revision History:
25 
26 --*/
27 
28 #ifndef _FXIOTARGETKM_H_
29 #define _FXIOTARGETKM_H_
30 
31 __inline
32 FxIoContext::FxIoContext(
33     VOID
34     ) :
35     FxRequestContext(FX_RCT_IO),
36     m_MdlToFree(NULL),
37     m_OriginalMdl(NULL),
38     m_BufferToFree(NULL),
39     m_OriginalSystemBuffer(NULL),
40     m_OriginalUserBuffer(NULL),
41     m_OtherMemory(NULL),
42     m_CopyBackToBuffer(FALSE),
43     m_UnlockPages(FALSE),
44     m_RestoreState(FALSE),
45     m_BufferToFreeLength(0),
46     m_MdlToFreeSize(0)
47 {
48 }
49 
50 __inline
51 FxIoContext::~FxIoContext(
52     VOID
53     )
54 {
55     //
56     // Free the buffer allocated for the request, reset m_CopyBackToBuffer
57     // to FALSE.
58     // NOTE: We delay the freeing of the buffer on purpose.
59     //
60     ClearBuffer();
61 
62     //
63     // Free the MDL allocated for the request
64     //
65     if (m_MdlToFree != NULL) {
66         //
67         // Being defensive here, MmUnlockPages should have been done in
68         // ReleaseAndRestore.
69         //
70         if (m_UnlockPages) {
71             MmUnlockPages(m_MdlToFree);
72             m_UnlockPages = FALSE;
73         }
74 
75         FxMdlFree(m_DriverGlobals, m_MdlToFree);
76         m_MdlToFree = NULL;
77     }
78 }
79 
80 __inline
81 VOID
82 FxIoContext::ReleaseAndRestore(
83     __in FxRequestBase* Request
84     )
85 {
86     FxIrp* irp = NULL;
87 
88     irp = Request->GetSubmitFxIrp();
89 
90     if (m_RestoreState) {
91         irp->SetSystemBuffer(m_OriginalSystemBuffer);
92         irp->SetUserBuffer(m_OriginalUserBuffer);
93         irp->SetMdlAddress(m_OriginalMdl);
94         irp->SetFlags(m_OriginalFlags);
95         m_OriginalSystemBuffer = NULL;
96         m_OriginalUserBuffer = NULL;
97         m_OriginalMdl = NULL;
98         m_OriginalFlags = NULL;
99 
100         m_RestoreState = FALSE;
101     }
102 
103     //
104     // If there was a buffer present don't free the buffer here so that
105     // it can be reused for any request with the same size.
106     // Similarly if there was an MDL to be freed unlock the pages but dont free
107     // the Mdl so that it can be reused.
108     //
109     if (m_MdlToFree != NULL) {
110         if (m_UnlockPages) {
111             MmUnlockPages(m_MdlToFree);
112             m_UnlockPages = FALSE;
113         }
114 
115 
116         m_DriverGlobals = Request->GetDriverGlobals();
117     }
118 
119     //
120     // Release the 2ndary buffer if we have an outstanding reference
121     //
122     if (m_OtherMemory != NULL) {
123         m_OtherMemory->RELEASE(this);
124         m_OtherMemory = NULL;
125     }
126 
127     //
128     // Release the other buffer and all __super related fields
129     //
130     FxRequestContext::ReleaseAndRestore(Request); // __super call
131 }
132 
133 __inline
134 VOID
135 FxIoContext::ClearBuffer(
136     VOID
137     )
138 {
139     if (m_BufferToFree != NULL) {
140         FxPoolFree(m_BufferToFree);
141         m_BufferToFree = NULL;
142     }
143 
144     m_BufferToFreeLength = 0;
145     m_CopyBackToBuffer = FALSE;
146 }
147 
148 __inline
149 VOID
150 FxIoContext::CopyParameters(
151     __in FxRequestBase* Request
152     )
153 {
154     switch (m_MajorFunction) {
155     case IRP_MJ_WRITE:
156         m_CompletionParams.Parameters.Write.Length =
157             m_CompletionParams.IoStatus.Information;
158         break;
159 
160     case IRP_MJ_READ:
161         m_CompletionParams.Parameters.Read.Length =
162             m_CompletionParams.IoStatus.Information;
163         break;
164 
165     case IRP_MJ_DEVICE_CONTROL:
166     case IRP_MJ_INTERNAL_DEVICE_CONTROL:
167         m_CompletionParams.Parameters.Ioctl.Output.Length =
168             m_CompletionParams.IoStatus.Information;
169         break;
170 
171     default:
172         ASSERT(FALSE);
173     }
174 
175     if (m_BufferToFree == NULL) {
176         return;
177     }
178 
179     if (m_CopyBackToBuffer) {
180         FxIrp* irp = Request->GetSubmitFxIrp();
181 
182         if (irp->GetUserBuffer() != NULL) {
183             //
184             // UserBuffer contains the caller's original output buffer.
185             // Copy the results back into the original buffer.
186             //
187             if (m_MajorFunction == IRP_MJ_DEVICE_CONTROL ||
188                 m_MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) {
189                 ASSERT(irp->GetInformation() <= m_BufferToFreeLength);
190             }
191 
192             RtlCopyMemory(irp->GetUserBuffer(),
193                           m_BufferToFree,
194                           irp->GetInformation());
195             m_CopyBackToBuffer = FALSE;
196         }
197     }
198 }
199 
200 __inline
201 VOID
202 FxIoContext::CaptureState(
203     __in FxIrp* Irp
204     )
205 {
206     m_RestoreState = TRUE;
207     m_OriginalSystemBuffer = Irp->GetSystemBuffer();
208     m_OriginalUserBuffer = Irp->GetUserBuffer();
209     m_OriginalMdl = Irp->GetMdl();
210     m_OriginalFlags = Irp->GetFlags();
211 }
212 
213 __inline
214 VOID
215 FxIoContext::SetBufferAndLength(
216     __in PVOID Buffer,
217     __in size_t   BufferLength,
218     __in BOOLEAN CopyBackToBuffer
219     )
220 {
221     PVOID pOldBuffer;
222 
223     pOldBuffer = m_BufferToFree;
224     m_BufferToFree = Buffer;
225     m_BufferToFreeLength = BufferLength;
226     m_CopyBackToBuffer = CopyBackToBuffer;
227 
228     if (pOldBuffer != NULL) {
229         FxPoolFree(pOldBuffer);
230     }
231 }
232 
233 
234 __inline
235 _Must_inspect_result_
236 NTSTATUS
237 FxIoTarget::InitModeSpecific(
238     __in CfxDeviceBase* Device
239     )
240 {
241     UNREFERENCED_PARAMETER(Device);
242 
243     DO_NOTHING();
244 
245     return STATUS_SUCCESS;
246 }
247 
248 __inline
249 BOOLEAN
250 FxIoTarget::HasValidStackSize(
251     VOID
252     )
253 {
254     return (m_TargetStackSize == 0 ? FALSE : TRUE);
255 }
256 
257 __inline
258 VOID
259 FxIoTarget::Send(
260     _In_ MdIrp Irp
261     )
262 {
263     //
264     // Ignore the return value because once we have sent the request, we
265     // want all processing to be done in the completion routine.
266     //
267     (void) IoCallDriver(m_TargetDevice, Irp);
268 }
269 
270 #endif // _FXIOTARGETKM_H_
271