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