2003-05-16 Casper S. Hornstrup <chorns@users.sourceforge.net>
[reactos.git] / reactos / ntoskrnl / io / irp.c
1 /* $Id: irp.c,v 1.48 2003/05/16 12:03:11 chorns Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/io/irp.c
6 * PURPOSE: Handle IRPs
7 * PROGRAMMER: David Welch (welch@mcmail.com)
8 * UPDATE HISTORY:
9 * 24/05/98: Created
10 */
11
12 /* NOTES *******************************************************************
13 *
14 * Layout of an IRP
15 *
16 * ################
17 * # Headers #
18 * ################
19 * # #
20 * # Variable #
21 * # length list #
22 * # of io stack #
23 * # locations #
24 * # #
25 * ################
26 *
27 *
28 *
29 */
30
31 /* INCLUDES ****************************************************************/
32
33 #include <ddk/ntddk.h>
34 #include <internal/io.h>
35 #include <internal/ps.h>
36 #include <internal/pool.h>
37
38 #define NDEBUG
39 #include <internal/debug.h>
40
41 /* GLOBALS *******************************************************************/
42
43 #define TAG_IRP TAG('I', 'R', 'P', ' ')
44
45
46 /* FUNCTIONS ****************************************************************/
47
48
49 VOID STDCALL
50 IoFreeIrp(PIRP Irp)
51 /*
52 * FUNCTION: Releases a caller allocated irp
53 * ARGUMENTS:
54 * Irp = Irp to free
55 */
56 {
57 ExFreePool(Irp);
58 }
59
60
61 PIRP STDCALL
62 IoMakeAssociatedIrp(PIRP Irp,
63 CCHAR StackSize)
64 /*
65 * FUNCTION: Allocates and initializes an irp to associated with a master irp
66 * ARGUMENTS:
67 * Irp = Master irp
68 * StackSize = Number of stack locations to be allocated in the irp
69 * RETURNS: The irp allocated
70 */
71 {
72 PIRP AssocIrp;
73
74 AssocIrp = IoAllocateIrp(StackSize,FALSE);
75 UNIMPLEMENTED;
76 return NULL;
77 }
78
79
80 VOID STDCALL
81 IoInitializeIrp(PIRP Irp,
82 USHORT PacketSize,
83 CCHAR StackSize)
84 /*
85 * FUNCTION: Initalizes an irp allocated by the caller
86 * ARGUMENTS:
87 * Irp = IRP to initalize
88 * PacketSize = Size in bytes of the IRP
89 * StackSize = Number of stack locations in the IRP
90 */
91 {
92 assert(Irp != NULL);
93
94 memset(Irp, 0, PacketSize);
95 Irp->Size = PacketSize;
96 Irp->StackCount = StackSize;
97 Irp->CurrentLocation = StackSize;
98 Irp->Tail.Overlay.CurrentStackLocation = &Irp->Stack[(ULONG)StackSize];
99 }
100
101
102 NTSTATUS FASTCALL
103 IofCallDriver(PDEVICE_OBJECT DeviceObject,
104 PIRP Irp)
105 /*
106 * FUNCTION: Sends an IRP to the next lower driver
107 */
108 {
109 PDRIVER_OBJECT DriverObject;
110 PIO_STACK_LOCATION Param;
111
112 DPRINT("IofCallDriver(DeviceObject %x, Irp %x)\n",DeviceObject,Irp);
113
114 assert(Irp);
115 assert(DeviceObject);
116
117 DriverObject = DeviceObject->DriverObject;
118
119 assert(DriverObject);
120
121 IoSetNextIrpStackLocation(Irp);
122 Param = IoGetCurrentIrpStackLocation(Irp);
123
124 DPRINT("IrpSp 0x%X\n", Param);
125
126 Param->DeviceObject = DeviceObject;
127
128 DPRINT("MajorFunction %d\n", Param->MajorFunction);
129 DPRINT("DriverObject->MajorFunction[Param->MajorFunction] %x\n",
130 DriverObject->MajorFunction[Param->MajorFunction]);
131
132 if ((Param->FileObject) && (Param->MajorFunction != IRP_MJ_CLOSE))
133 {
134 ObReferenceObject(Param->FileObject);
135 }
136
137 return DriverObject->MajorFunction[Param->MajorFunction](DeviceObject, Irp);
138 }
139
140
141 NTSTATUS
142 STDCALL
143 IoCallDriver (PDEVICE_OBJECT DeviceObject, PIRP Irp)
144 {
145 return(IofCallDriver(DeviceObject,
146 Irp));
147 }
148
149
150 PIRP STDCALL
151 IoAllocateIrp(CCHAR StackSize,
152 BOOLEAN ChargeQuota)
153 /*
154 * FUNCTION: Allocates an IRP
155 * ARGUMENTS:
156 * StackSize = the size of the stack required for the irp
157 * ChargeQuota = Charge allocation to current threads quota
158 * RETURNS: Irp allocated
159 */
160 {
161 PIRP Irp;
162
163 #if 0
164 DbgPrint("IoAllocateIrp(StackSize %d ChargeQuota %d)\n",
165 StackSize,
166 ChargeQuota);
167 KeDumpStackFrames(0,8);
168 #endif
169
170 if (ChargeQuota)
171 {
172 // Irp = ExAllocatePoolWithQuota(NonPagedPool,IoSizeOfIrp(StackSize));
173 Irp = ExAllocatePoolWithTag(NonPagedPool,
174 IoSizeOfIrp(StackSize),
175 TAG_IRP);
176 }
177 else
178 {
179 Irp = ExAllocatePoolWithTag(NonPagedPool,
180 IoSizeOfIrp(StackSize),
181 TAG_IRP);
182 }
183
184 if (Irp==NULL)
185 {
186 return(NULL);
187 }
188
189 IoInitializeIrp(Irp,
190 IoSizeOfIrp(StackSize),
191 StackSize);
192
193 // DPRINT("Irp %x Irp->StackPtr %d\n", Irp, Irp->CurrentLocation);
194
195 return(Irp);
196 }
197
198
199 VOID STDCALL
200 IopCompleteRequest(struct _KAPC* Apc,
201 PKNORMAL_ROUTINE* NormalRoutine,
202 PVOID* NormalContext,
203 PVOID* SystemArgument1,
204 PVOID* SystemArgument2)
205 {
206 DPRINT("IopCompleteRequest(Apc %x, SystemArgument1 %x, (*SystemArgument1) %x\n",
207 Apc,
208 SystemArgument1,
209 *SystemArgument1);
210 IoSecondStageCompletion((PIRP)(*SystemArgument1),
211 (KPRIORITY)(*SystemArgument2));
212 }
213
214
215 VOID FASTCALL
216 IofCompleteRequest(PIRP Irp,
217 CCHAR PriorityBoost)
218 /*
219 * FUNCTION: Indicates the caller has finished all processing for a given
220 * I/O request and is returning the given IRP to the I/O manager
221 * ARGUMENTS:
222 * Irp = Irp to be cancelled
223 * PriorityBoost = Increment by which to boost the priority of the
224 * thread making the request
225 */
226 {
227 ULONG i;
228 NTSTATUS Status;
229 PDEVICE_OBJECT DeviceObject;
230
231 DPRINT("IoCompleteRequest(Irp %x, PriorityBoost %d) Event %x THread %x\n",
232 Irp,PriorityBoost, Irp->UserEvent, PsGetCurrentThread());
233
234 assert(Irp->CancelRoutine == NULL);
235 assert(Irp->IoStatus.Status != STATUS_PENDING);
236
237 if (IoGetCurrentIrpStackLocation(Irp)->Control & SL_PENDING_RETURNED)
238 {
239 Irp->PendingReturned = TRUE;
240 }
241
242 for (i=Irp->CurrentLocation;i<(ULONG)Irp->StackCount;i++)
243 {
244 /*
245 Completion routines expect the current irp stack location to be the same as when
246 IoSetCompletionRoutine was called to set them. A side effect is that completion
247 routines set by highest level drivers without their own stack location will receive
248 an invalid current stack location (at least it should be considered as invalid).
249 Since the DeviceObject argument passed is taken from the current stack, this value
250 is also invalid (NULL).
251 */
252 if (Irp->CurrentLocation < Irp->StackCount - 1)
253 {
254 IoSetPreviousIrpStackLocation(Irp);
255 DeviceObject = IoGetCurrentIrpStackLocation(Irp)->DeviceObject;
256 }
257 else
258 {
259 DeviceObject = NULL;
260 }
261
262 if (Irp->Stack[i].CompletionRoutine != NULL &&
263 ((NT_SUCCESS(Irp->IoStatus.Status) && (Irp->Stack[i].Control & SL_INVOKE_ON_SUCCESS)) ||
264 (!NT_SUCCESS(Irp->IoStatus.Status) && (Irp->Stack[i].Control & SL_INVOKE_ON_ERROR)) ||
265 (Irp->Cancel && (Irp->Stack[i].Control & SL_INVOKE_ON_CANCEL))))
266 {
267 Status = Irp->Stack[i].CompletionRoutine(DeviceObject,
268 Irp,
269 Irp->Stack[i].CompletionContext);
270
271 if (Status == STATUS_MORE_PROCESSING_REQUIRED)
272 {
273 return;
274 }
275 }
276
277 if (IoGetCurrentIrpStackLocation(Irp)->Control & SL_PENDING_RETURNED)
278 {
279 Irp->PendingReturned = TRUE;
280 }
281 }
282
283 if (Irp->PendingReturned)
284 {
285 DPRINT("Dispatching APC\n");
286 KeInitializeApc(&Irp->Tail.Apc,
287 &Irp->Tail.Overlay.Thread->Tcb,
288 0,
289 IopCompleteRequest,
290 NULL,
291 (PKNORMAL_ROUTINE)
292 NULL,
293 KernelMode,
294 NULL);
295 KeInsertQueueApc(&Irp->Tail.Apc,
296 (PVOID)Irp,
297 (PVOID)(ULONG)PriorityBoost,
298 KernelMode);
299 DPRINT("Finished dispatching APC\n");
300 }
301 else
302 {
303 DPRINT("Calling completion routine directly\n");
304 IoSecondStageCompletion(Irp,PriorityBoost);
305 DPRINT("Finished completition routine\n");
306 }
307 }
308
309
310 VOID STDCALL
311 IoCompleteRequest(PIRP Irp,
312 CCHAR PriorityBoost)
313 {
314 IofCompleteRequest(Irp,
315 PriorityBoost);
316 }
317
318
319 /**********************************************************************
320 * NAME EXPORTED
321 * IoIsOperationSynchronous@4
322 *
323 * DESCRIPTION
324 * Check if the I/O operation associated with the given IRP
325 * is synchronous.
326 *
327 * ARGUMENTS
328 * Irp Packet to check.
329 *
330 * RETURN VALUE
331 * TRUE if Irp's operation is synchronous; otherwise FALSE.
332 */
333 BOOLEAN STDCALL
334 IoIsOperationSynchronous(IN PIRP Irp)
335 {
336 PFILE_OBJECT FileObject = NULL;
337 ULONG Flags = 0;
338
339 /* Check the FILE_OBJECT's flags first. */
340 FileObject = IoGetCurrentIrpStackLocation(Irp)->FileObject;
341 if (!(FO_SYNCHRONOUS_IO & FileObject->Flags))
342 {
343 /* Check IRP's flags. */
344 Flags = Irp->Flags;
345 if (!((IRP_SYNCHRONOUS_API | IRP_SYNCHRONOUS_PAGING_IO) & Flags))
346 {
347 return(FALSE);
348 }
349 }
350
351 /* Check more IRP's flags. */
352 Flags = Irp->Flags;
353 if (!(IRP_PAGING_IO & Flags)
354 || (IRP_SYNCHRONOUS_PAGING_IO & Flags))
355 {
356 return(TRUE);
357 }
358
359 /* Otherwise, it is an asynchronous operation. */
360 return(FALSE);
361 }
362
363
364 VOID STDCALL
365 IoEnqueueIrp(IN PIRP Irp)
366 {
367 UNIMPLEMENTED;
368 }
369
370
371 VOID STDCALL
372 IoSetTopLevelIrp(IN PIRP Irp)
373 {
374 PETHREAD Thread;
375
376 Thread = PsGetCurrentThread();
377 Thread->TopLevelIrp->TopLevelIrp = Irp;
378 }
379
380
381 PIRP STDCALL
382 IoGetTopLevelIrp(VOID)
383 {
384 return(PsGetCurrentThread()->TopLevelIrp->TopLevelIrp);
385 }
386
387
388 VOID STDCALL
389 IoQueueThreadIrp(IN PIRP Irp)
390 {
391 UNIMPLEMENTED;
392 }
393
394 /*
395 NTSTATUS
396 STDCALL
397 IoSetDeviceInterfaceState(IN PUNICODE_STRING SymbolicLinkName, IN BOOLEAN Enable)
398 {
399 UNIMPLEMENTED;
400 return 0;
401 }
402
403 NTSTATUS
404 STDCALL
405 IoGetDeviceProperty(
406 IN PDEVICE_OBJECT DeviceObject,
407 IN DEVICE_REGISTRY_PROPERTY DeviceProperty,
408 IN ULONG BufferLength,
409 OUT PVOID PropertyBuffer,
410 OUT PULONG ResultLength)
411 {
412 UNIMPLEMENTED;
413 return 0;
414 }
415
416 NTSTATUS
417 STDCALL
418 IoOpenDeviceRegistryKey(
419 IN PDEVICE_OBJECT DeviceObject,
420 IN ULONG DevInstKeyType,
421 IN ACCESS_MASK DesiredAccess,
422 OUT PHANDLE DevInstRegKey)
423 {
424 UNIMPLEMENTED;
425 return 0;
426 }
427 */
428 /* EOF */