cfaf25535950f6912bd75318c93508b9d134499d
[reactos.git] / ntoskrnl / io / irp.c
1 /* $Id$
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 #ifndef LIBCAPTIVE
61
62 PIRP STDCALL
63 IoMakeAssociatedIrp(PIRP Irp,
64                     CCHAR StackSize)
65 /*
66  * FUNCTION: Allocates and initializes an irp to associated with a master irp
67  * ARGUMENTS:
68  *       Irp = Master irp
69  *       StackSize = Number of stack locations to be allocated in the irp
70  * RETURNS: The irp allocated
71  */
72 {
73   PIRP AssocIrp;
74   
75   AssocIrp = IoAllocateIrp(StackSize,FALSE);
76   UNIMPLEMENTED;
77   return NULL;
78 }
79
80 #endif /* LIBCAPTIVE */
81
82 VOID STDCALL
83 IoInitializeIrp(PIRP Irp,
84                 USHORT PacketSize,
85                 CCHAR StackSize)
86 /*
87  * FUNCTION: Initalizes an irp allocated by the caller
88  * ARGUMENTS:
89  *          Irp = IRP to initalize
90  *          PacketSize = Size in bytes of the IRP
91  *          StackSize = Number of stack locations in the IRP
92  */
93 {
94   assert(Irp != NULL);
95
96   memset(Irp, 0, PacketSize);
97   Irp->Type = IO_TYPE_IRP;
98   Irp->Size = PacketSize;
99   Irp->StackCount = StackSize;
100   Irp->CurrentLocation = StackSize;
101   Irp->Tail.Overlay.CurrentStackLocation = &Irp->Stack[(ULONG)StackSize];
102 }
103
104
105 NTSTATUS FASTCALL
106 IofCallDriver(PDEVICE_OBJECT DeviceObject,
107               PIRP Irp)
108 /*
109   * FUNCTION: Sends an IRP to the next lower driver
110  */
111 {
112   PDRIVER_OBJECT DriverObject;
113   PIO_STACK_LOCATION Param;
114   
115   DPRINT("IofCallDriver(DeviceObject %x, Irp %x)\n",DeviceObject,Irp);
116   
117   assert(Irp);
118   assert(DeviceObject);
119
120   DriverObject = DeviceObject->DriverObject;
121
122   assert(DriverObject);
123
124   IoSetNextIrpStackLocation(Irp);
125   Param = IoGetCurrentIrpStackLocation(Irp);
126
127   DPRINT("IrpSp 0x%X\n", Param);
128   
129   Param->DeviceObject = DeviceObject;
130
131   DPRINT("MajorFunction %d\n", Param->MajorFunction);
132   DPRINT("DriverObject->MajorFunction[Param->MajorFunction] %x\n",
133     DriverObject->MajorFunction[Param->MajorFunction]);
134
135   if (!DriverObject->MajorFunction[Param->MajorFunction])
136     {
137       if (Param->MajorFunction==IRP_MJ_FLUSH_BUFFERS)
138         {
139           ObDereferenceObject(Param->FileObject);
140           return STATUS_SUCCESS;
141         }
142       KeBugCheck(0);
143     }
144   return DriverObject->MajorFunction[Param->MajorFunction](DeviceObject, Irp);
145 }
146
147
148 NTSTATUS
149 STDCALL
150 IoCallDriver (PDEVICE_OBJECT DeviceObject, PIRP Irp)
151 {
152   return(IofCallDriver(DeviceObject,
153                        Irp));
154 }
155
156
157 PIRP STDCALL
158 IoAllocateIrp(CCHAR StackSize,
159               BOOLEAN ChargeQuota)
160 /*
161  * FUNCTION: Allocates an IRP
162  * ARGUMENTS:
163  *          StackSize = the size of the stack required for the irp
164  *          ChargeQuota = Charge allocation to current threads quota
165  * RETURNS: Irp allocated
166  */
167 {
168   PIRP Irp;
169
170 #if 0
171   DbgPrint("IoAllocateIrp(StackSize %d ChargeQuota %d)\n",
172            StackSize,
173            ChargeQuota);
174   KeDumpStackFrames(0,8);
175 #endif
176   
177   if (ChargeQuota)
178     {
179 //      Irp = ExAllocatePoolWithQuota(NonPagedPool,IoSizeOfIrp(StackSize));
180       Irp = ExAllocatePoolWithTag(NonPagedPool,
181                                   IoSizeOfIrp(StackSize),
182                                   TAG_IRP);
183     }
184   else
185     {
186       Irp = ExAllocatePoolWithTag(NonPagedPool,
187                                   IoSizeOfIrp(StackSize),
188                                   TAG_IRP);
189     }
190
191   if (Irp==NULL)
192     {
193       return(NULL);
194     }
195
196   IoInitializeIrp(Irp,
197                   IoSizeOfIrp(StackSize),
198                   StackSize);
199
200 //  DPRINT("Irp %x Irp->StackPtr %d\n", Irp, Irp->CurrentLocation);
201
202   return(Irp);
203 }
204
205 #ifndef LIBCAPTIVE
206
207 VOID STDCALL
208 IopCompleteRequest(struct _KAPC* Apc,
209                    PKNORMAL_ROUTINE* NormalRoutine,
210                    PVOID* NormalContext,
211                    PVOID* SystemArgument1,
212                    PVOID* SystemArgument2)
213 {
214   DPRINT("IopCompleteRequest(Apc %x, SystemArgument1 %x, (*SystemArgument1) %x\n",
215          Apc,
216          SystemArgument1,
217          *SystemArgument1);
218   IoSecondStageCompletion((PIRP)(*SystemArgument1),
219                           (KPRIORITY)(*SystemArgument2));
220 }
221
222 #endif /* LIBCAPTIVE */
223
224
225 #ifdef LIBCAPTIVE
226 /* file-scope of libcaptive/io/irp.c: */
227 extern void IofCompleteRequest_register_APC(PIRP Irp,CCHAR PriorityBoost);
228 #endif /* LIBCAPTIVE */
229
230 VOID FASTCALL
231 IofCompleteRequest(PIRP Irp,
232                    CCHAR PriorityBoost)
233 /*
234  * FUNCTION: Indicates the caller has finished all processing for a given
235  * I/O request and is returning the given IRP to the I/O manager
236  * ARGUMENTS:
237  *         Irp = Irp to be cancelled
238  *         PriorityBoost = Increment by which to boost the priority of the
239  *                         thread making the request
240  */
241 {
242    ULONG             i;
243    NTSTATUS          Status;
244    PDEVICE_OBJECT    DeviceObject;
245
246    DPRINT("IoCompleteRequest(Irp %x, PriorityBoost %d) Event %x THread %x\n",
247       Irp,PriorityBoost, Irp->UserEvent, PsGetCurrentThread());
248
249    assert(Irp->CancelRoutine == NULL);
250    assert(Irp->IoStatus.Status != STATUS_PENDING);
251
252    if (IoGetCurrentIrpStackLocation(Irp)->Control & SL_PENDING_RETURNED)
253    {
254       Irp->PendingReturned = TRUE;
255    }
256
257    for (i=Irp->CurrentLocation;i<(ULONG)Irp->StackCount;i++)
258    {
259       /*
260       Completion routines expect the current irp stack location to be the same as when
261       IoSetCompletionRoutine was called to set them. A side effect is that completion
262       routines set by highest level drivers without their own stack location will receive
263       an invalid current stack location (at least it should be considered as invalid).
264       Since the DeviceObject argument passed is taken from the current stack, this value
265       is also invalid (NULL).
266       */
267       if (Irp->CurrentLocation < Irp->StackCount - 1)
268       {
269          IoSetPreviousIrpStackLocation(Irp);
270          DeviceObject = IoGetCurrentIrpStackLocation(Irp)->DeviceObject;
271       }
272       else
273       {
274          DeviceObject = NULL;
275       }
276
277       if (Irp->Stack[i].CompletionRoutine != NULL &&
278          ((NT_SUCCESS(Irp->IoStatus.Status) && (Irp->Stack[i].Control & SL_INVOKE_ON_SUCCESS)) ||
279          (!NT_SUCCESS(Irp->IoStatus.Status) && (Irp->Stack[i].Control & SL_INVOKE_ON_ERROR)) ||
280          (Irp->Cancel && (Irp->Stack[i].Control & SL_INVOKE_ON_CANCEL))))
281       {
282          Status = Irp->Stack[i].CompletionRoutine(DeviceObject,
283                                                   Irp,
284                                                   Irp->Stack[i].CompletionContext);
285
286          if (Status == STATUS_MORE_PROCESSING_REQUIRED)
287          {
288             if (Irp->UserIosb)
289                {
290                   *Irp->UserIosb=Irp->IoStatus;
291                }
292             return;
293          }
294       }
295    
296       if (IoGetCurrentIrpStackLocation(Irp)->Control & SL_PENDING_RETURNED)
297       {
298          Irp->PendingReturned = TRUE;
299       }
300    }
301
302    if (Irp->PendingReturned)
303      {
304 #ifdef LIBCAPTIVE
305         /* FIXME: Why the hell should we bother with some damned APCs?!?
306          * Call it directly below!
307          */
308         DPRINT("IofCompleteRequest() dispatching APC: using g_idle_add_full()\n");
309         IofCompleteRequest_register_APC(Irp,PriorityBoost);
310 #else /* !LIBCAPTIVE */
311         DPRINT("Dispatching APC\n");
312         KeInitializeApc(&Irp->Tail.Apc,
313                         &Irp->Tail.Overlay.Thread->Tcb,
314                         0,
315                         IopCompleteRequest,
316                         NULL,
317                         (PKNORMAL_ROUTINE)
318                         NULL,
319                         KernelMode,
320                         NULL);
321         KeInsertQueueApc(&Irp->Tail.Apc,
322                          (PVOID)Irp,
323                          (PVOID)(ULONG)PriorityBoost,
324                          KernelMode);
325 #endif /* !LIBCAPTIVE */
326         DPRINT("Finished dispatching APC\n");
327      }
328    else
329      {
330         DPRINT("Calling completion routine directly\n");
331         IoSecondStageCompletion(Irp,PriorityBoost);
332         DPRINT("Finished completition routine\n");
333      }
334 }
335
336
337 VOID STDCALL
338 IoCompleteRequest(PIRP Irp,
339                   CCHAR PriorityBoost)
340 {
341   IofCompleteRequest(Irp,
342                      PriorityBoost);
343 }
344
345
346 /**********************************************************************
347  * NAME                                                 EXPORTED
348  *      IoIsOperationSynchronous@4
349  *
350  * DESCRIPTION
351  *      Check if the I/O operation associated with the given IRP
352  *      is synchronous.
353  *
354  * ARGUMENTS
355  *      Irp     Packet to check.
356  *
357  * RETURN VALUE
358  *      TRUE if Irp's operation is synchronous; otherwise FALSE.
359  */
360 BOOLEAN STDCALL
361 IoIsOperationSynchronous(IN PIRP Irp)
362 {
363   PFILE_OBJECT FileObject = NULL;
364   ULONG Flags = 0;
365
366   /* Check the FILE_OBJECT's flags first. */
367   FileObject = IoGetCurrentIrpStackLocation(Irp)->FileObject;
368   if (FileObject == NULL)
369     KeBugCheck(0);
370   if (!(FO_SYNCHRONOUS_IO & FileObject->Flags))
371     {
372       /* Check IRP's flags. */
373       Flags = Irp->Flags;
374       if (!((IRP_SYNCHRONOUS_API | IRP_SYNCHRONOUS_PAGING_IO) & Flags))
375         {
376 #ifdef LIBCAPTIVE
377           /* libcaptive is fully single-thread/single-process synchronous model. */
378           return TRUE;
379 #endif /* LIBCAPTIVE */
380           return(FALSE);
381         }
382     }
383
384   /* Check more IRP's flags. */
385   Flags = Irp->Flags;
386   if (!(IRP_PAGING_IO & Flags)
387       || (IRP_SYNCHRONOUS_PAGING_IO & Flags))
388     {
389       return(TRUE);
390     }
391
392   /* Otherwise, it is an asynchronous operation. */
393 #ifdef LIBCAPTIVE
394   /* libcaptive is fully single-thread/single-process synchronous model. */
395   return TRUE;
396 #endif /* LIBCAPTIVE */
397   return(FALSE);
398 }
399
400 #ifndef LIBCAPTIVE
401
402 VOID STDCALL
403 IoEnqueueIrp(IN PIRP Irp)
404 {
405   UNIMPLEMENTED;
406 }
407
408 #endif /* LIBCAPTIVE */
409
410 VOID STDCALL
411 IoSetTopLevelIrp(IN PIRP Irp)
412 {
413   PETHREAD Thread;
414
415   Thread = PsGetCurrentThread();
416   Thread->TopLevelIrp->TopLevelIrp = Irp;
417 }
418
419
420 PIRP STDCALL
421 IoGetTopLevelIrp(VOID)
422 {
423   return(PsGetCurrentThread()->TopLevelIrp->TopLevelIrp);
424 }
425
426 #ifndef LIBCAPTIVE
427
428 VOID STDCALL
429 IoQueueThreadIrp(IN PIRP Irp)
430 {
431   UNIMPLEMENTED;
432 }
433
434 /*
435 NTSTATUS
436 STDCALL
437 IoSetDeviceInterfaceState(IN PUNICODE_STRING SymbolicLinkName, IN BOOLEAN Enable)
438 {
439   UNIMPLEMENTED;
440         return 0;
441 }
442
443 NTSTATUS
444 STDCALL
445 IoGetDeviceProperty(
446   IN PDEVICE_OBJECT DeviceObject,
447   IN DEVICE_REGISTRY_PROPERTY DeviceProperty,
448   IN ULONG BufferLength,
449   OUT PVOID PropertyBuffer,
450   OUT PULONG ResultLength)
451 {
452   UNIMPLEMENTED;
453         return 0;
454 }
455
456 NTSTATUS
457 STDCALL
458 IoOpenDeviceRegistryKey(
459   IN PDEVICE_OBJECT DeviceObject,
460   IN ULONG DevInstKeyType,
461   IN ACCESS_MASK DesiredAccess,
462   OUT PHANDLE DevInstRegKey)
463 {
464   UNIMPLEMENTED;
465         return 0;
466 }
467  */
468
469 #endif /* LIBCAPTIVE */
470
471 /* EOF */