2d40f45bbe9a18171efdc0f8c17af7d3dc8acb01
[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     KeBugCheck(0);
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 #ifndef LIBCAPTIVE
199
200 VOID STDCALL
201 IopCompleteRequest(struct _KAPC* Apc,
202                    PKNORMAL_ROUTINE* NormalRoutine,
203                    PVOID* NormalContext,
204                    PVOID* SystemArgument1,
205                    PVOID* SystemArgument2)
206 {
207   DPRINT("IopCompleteRequest(Apc %x, SystemArgument1 %x, (*SystemArgument1) %x\n",
208          Apc,
209          SystemArgument1,
210          *SystemArgument1);
211   IoSecondStageCompletion((PIRP)(*SystemArgument1),
212                           (KPRIORITY)(*SystemArgument2));
213 }
214
215 #endif /* LIBCAPTIVE */
216
217
218 #ifdef LIBCAPTIVE
219 /* file-scope of libcaptive/io/irp.c: */
220 extern void IofCompleteRequest_register_APC(PIRP Irp,CCHAR PriorityBoost);
221 #endif /* LIBCAPTIVE */
222
223 VOID FASTCALL
224 IofCompleteRequest(PIRP Irp,
225                    CCHAR PriorityBoost)
226 /*
227  * FUNCTION: Indicates the caller has finished all processing for a given
228  * I/O request and is returning the given IRP to the I/O manager
229  * ARGUMENTS:
230  *         Irp = Irp to be cancelled
231  *         PriorityBoost = Increment by which to boost the priority of the
232  *                         thread making the request
233  */
234 {
235    ULONG             i;
236    NTSTATUS          Status;
237    PDEVICE_OBJECT    DeviceObject;
238
239    DPRINT("IoCompleteRequest(Irp %x, PriorityBoost %d) Event %x THread %x\n",
240       Irp,PriorityBoost, Irp->UserEvent, PsGetCurrentThread());
241
242    assert(Irp->CancelRoutine == NULL);
243    assert(Irp->IoStatus.Status != STATUS_PENDING);
244
245    if (IoGetCurrentIrpStackLocation(Irp)->Control & SL_PENDING_RETURNED)
246    {
247       Irp->PendingReturned = TRUE;
248    }
249
250    for (i=Irp->CurrentLocation;i<(ULONG)Irp->StackCount;i++)
251    {
252       /*
253       Completion routines expect the current irp stack location to be the same as when
254       IoSetCompletionRoutine was called to set them. A side effect is that completion
255       routines set by highest level drivers without their own stack location will receive
256       an invalid current stack location (at least it should be considered as invalid).
257       Since the DeviceObject argument passed is taken from the current stack, this value
258       is also invalid (NULL).
259       */
260       if (Irp->CurrentLocation < Irp->StackCount - 1)
261       {
262          IoSetPreviousIrpStackLocation(Irp);
263          DeviceObject = IoGetCurrentIrpStackLocation(Irp)->DeviceObject;
264       }
265       else
266       {
267          DeviceObject = NULL;
268       }
269
270       if (Irp->Stack[i].CompletionRoutine != NULL &&
271          ((NT_SUCCESS(Irp->IoStatus.Status) && (Irp->Stack[i].Control & SL_INVOKE_ON_SUCCESS)) ||
272          (!NT_SUCCESS(Irp->IoStatus.Status) && (Irp->Stack[i].Control & SL_INVOKE_ON_ERROR)) ||
273          (Irp->Cancel && (Irp->Stack[i].Control & SL_INVOKE_ON_CANCEL))))
274       {
275          Status = Irp->Stack[i].CompletionRoutine(DeviceObject,
276                                                   Irp,
277                                                   Irp->Stack[i].CompletionContext);
278
279          if (Status == STATUS_MORE_PROCESSING_REQUIRED)
280          {
281             if (Irp->UserIosb)
282                {
283                   *Irp->UserIosb=Irp->IoStatus;
284                }
285             return;
286          }
287       }
288    
289       if (IoGetCurrentIrpStackLocation(Irp)->Control & SL_PENDING_RETURNED)
290       {
291          Irp->PendingReturned = TRUE;
292       }
293    }
294
295    if (Irp->PendingReturned)
296      {
297 #ifdef LIBCAPTIVE
298         /* FIXME: Why the hell should we bother with some damned APCs?!?
299          * Call it directly below!
300          */
301         DPRINT("IofCompleteRequest() dispatching APC: using g_idle_add_full()\n");
302         IofCompleteRequest_register_APC(Irp,PriorityBoost);
303 #else /* !LIBCAPTIVE */
304         DPRINT("Dispatching APC\n");
305         KeInitializeApc(&Irp->Tail.Apc,
306                         &Irp->Tail.Overlay.Thread->Tcb,
307                         0,
308                         IopCompleteRequest,
309                         NULL,
310                         (PKNORMAL_ROUTINE)
311                         NULL,
312                         KernelMode,
313                         NULL);
314         KeInsertQueueApc(&Irp->Tail.Apc,
315                          (PVOID)Irp,
316                          (PVOID)(ULONG)PriorityBoost,
317                          KernelMode);
318 #endif /* !LIBCAPTIVE */
319         DPRINT("Finished dispatching APC\n");
320      }
321    else
322      {
323         DPRINT("Calling completion routine directly\n");
324         IoSecondStageCompletion(Irp,PriorityBoost);
325         DPRINT("Finished completition routine\n");
326      }
327 }
328
329
330 VOID STDCALL
331 IoCompleteRequest(PIRP Irp,
332                   CCHAR PriorityBoost)
333 {
334   IofCompleteRequest(Irp,
335                      PriorityBoost);
336 }
337
338
339 /**********************************************************************
340  * NAME                                                 EXPORTED
341  *      IoIsOperationSynchronous@4
342  *
343  * DESCRIPTION
344  *      Check if the I/O operation associated with the given IRP
345  *      is synchronous.
346  *
347  * ARGUMENTS
348  *      Irp     Packet to check.
349  *
350  * RETURN VALUE
351  *      TRUE if Irp's operation is synchronous; otherwise FALSE.
352  */
353 BOOLEAN STDCALL
354 IoIsOperationSynchronous(IN PIRP Irp)
355 {
356   PFILE_OBJECT FileObject = NULL;
357   ULONG Flags = 0;
358
359   /* Check the FILE_OBJECT's flags first. */
360   FileObject = IoGetCurrentIrpStackLocation(Irp)->FileObject;
361   if (FileObject == NULL)
362     KeBugCheck(0);
363   if (!(FO_SYNCHRONOUS_IO & FileObject->Flags))
364     {
365       /* Check IRP's flags. */
366       Flags = Irp->Flags;
367       if (!((IRP_SYNCHRONOUS_API | IRP_SYNCHRONOUS_PAGING_IO) & Flags))
368         {
369 #ifdef LIBCAPTIVE
370           /* libcaptive is fully single-thread/single-process synchronous model. */
371           return TRUE;
372 #endif /* LIBCAPTIVE */
373           return(FALSE);
374         }
375     }
376
377   /* Check more IRP's flags. */
378   Flags = Irp->Flags;
379   if (!(IRP_PAGING_IO & Flags)
380       || (IRP_SYNCHRONOUS_PAGING_IO & Flags))
381     {
382       return(TRUE);
383     }
384
385   /* Otherwise, it is an asynchronous operation. */
386 #ifdef LIBCAPTIVE
387   /* libcaptive is fully single-thread/single-process synchronous model. */
388   return TRUE;
389 #endif /* LIBCAPTIVE */
390   return(FALSE);
391 }
392
393 #ifndef LIBCAPTIVE
394
395 VOID STDCALL
396 IoEnqueueIrp(IN PIRP Irp)
397 {
398   UNIMPLEMENTED;
399 }
400
401 #endif /* LIBCAPTIVE */
402
403 VOID STDCALL
404 IoSetTopLevelIrp(IN PIRP Irp)
405 {
406   PETHREAD Thread;
407
408   Thread = PsGetCurrentThread();
409   Thread->TopLevelIrp->TopLevelIrp = Irp;
410 }
411
412
413 PIRP STDCALL
414 IoGetTopLevelIrp(VOID)
415 {
416   return(PsGetCurrentThread()->TopLevelIrp->TopLevelIrp);
417 }
418
419 #ifndef LIBCAPTIVE
420
421 VOID STDCALL
422 IoQueueThreadIrp(IN PIRP Irp)
423 {
424   UNIMPLEMENTED;
425 }
426
427 /*
428 NTSTATUS
429 STDCALL
430 IoSetDeviceInterfaceState(IN PUNICODE_STRING SymbolicLinkName, IN BOOLEAN Enable)
431 {
432   UNIMPLEMENTED;
433         return 0;
434 }
435
436 NTSTATUS
437 STDCALL
438 IoGetDeviceProperty(
439   IN PDEVICE_OBJECT DeviceObject,
440   IN DEVICE_REGISTRY_PROPERTY DeviceProperty,
441   IN ULONG BufferLength,
442   OUT PVOID PropertyBuffer,
443   OUT PULONG ResultLength)
444 {
445   UNIMPLEMENTED;
446         return 0;
447 }
448
449 NTSTATUS
450 STDCALL
451 IoOpenDeviceRegistryKey(
452   IN PDEVICE_OBJECT DeviceObject,
453   IN ULONG DevInstKeyType,
454   IN ACCESS_MASK DesiredAccess,
455   OUT PHANDLE DevInstRegKey)
456 {
457   UNIMPLEMENTED;
458         return 0;
459 }
460  */
461
462 #endif /* LIBCAPTIVE */
463
464 /* EOF */