c436611b288a11b48700fe1d4e8fe9443c58b8b5
[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
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   return DriverObject->MajorFunction[Param->MajorFunction](DeviceObject, Irp);
133 }
134
135
136 NTSTATUS
137 STDCALL
138 IoCallDriver (PDEVICE_OBJECT DeviceObject, PIRP Irp)
139 {
140   return(IofCallDriver(DeviceObject,
141                        Irp));
142 }
143
144
145 PIRP STDCALL
146 IoAllocateIrp(CCHAR StackSize,
147               BOOLEAN ChargeQuota)
148 /*
149  * FUNCTION: Allocates an IRP
150  * ARGUMENTS:
151  *          StackSize = the size of the stack required for the irp
152  *          ChargeQuota = Charge allocation to current threads quota
153  * RETURNS: Irp allocated
154  */
155 {
156   PIRP Irp;
157
158 #if 0
159   DbgPrint("IoAllocateIrp(StackSize %d ChargeQuota %d)\n",
160            StackSize,
161            ChargeQuota);
162   KeDumpStackFrames(0,8);
163 #endif
164   
165   if (ChargeQuota)
166     {
167 //      Irp = ExAllocatePoolWithQuota(NonPagedPool,IoSizeOfIrp(StackSize));
168       Irp = ExAllocatePoolWithTag(NonPagedPool,
169                                   IoSizeOfIrp(StackSize),
170                                   TAG_IRP);
171     }
172   else
173     {
174       Irp = ExAllocatePoolWithTag(NonPagedPool,
175                                   IoSizeOfIrp(StackSize),
176                                   TAG_IRP);
177     }
178
179   if (Irp==NULL)
180     {
181       return(NULL);
182     }
183
184   IoInitializeIrp(Irp,
185                   IoSizeOfIrp(StackSize),
186                   StackSize);
187
188 //  DPRINT("Irp %x Irp->StackPtr %d\n", Irp, Irp->CurrentLocation);
189
190   return(Irp);
191 }
192
193
194 VOID STDCALL
195 IopCompleteRequest(struct _KAPC* Apc,
196                    PKNORMAL_ROUTINE* NormalRoutine,
197                    PVOID* NormalContext,
198                    PVOID* SystemArgument1,
199                    PVOID* SystemArgument2)
200 {
201   DPRINT("IopCompleteRequest(Apc %x, SystemArgument1 %x, (*SystemArgument1) %x\n",
202          Apc,
203          SystemArgument1,
204          *SystemArgument1);
205   IoSecondStageCompletion((PIRP)(*SystemArgument1),
206                           (KPRIORITY)(*SystemArgument2));
207 }
208
209
210 VOID FASTCALL
211 IofCompleteRequest(PIRP Irp,
212                    CCHAR PriorityBoost)
213 /*
214  * FUNCTION: Indicates the caller has finished all processing for a given
215  * I/O request and is returning the given IRP to the I/O manager
216  * ARGUMENTS:
217  *         Irp = Irp to be cancelled
218  *         PriorityBoost = Increment by which to boost the priority of the
219  *                         thread making the request
220  */
221 {
222    ULONG             i;
223    NTSTATUS          Status;
224    PDEVICE_OBJECT    DeviceObject;
225
226    DPRINT("IoCompleteRequest(Irp %x, PriorityBoost %d) Event %x THread %x\n",
227       Irp,PriorityBoost, Irp->UserEvent, PsGetCurrentThread());
228
229    assert(Irp->CancelRoutine == NULL);
230    assert(Irp->IoStatus.Status != STATUS_PENDING);
231
232    if (IoGetCurrentIrpStackLocation(Irp)->Control & SL_PENDING_RETURNED)
233    {
234       Irp->PendingReturned = TRUE;
235    }
236
237    for (i=Irp->CurrentLocation;i<(ULONG)Irp->StackCount;i++)
238    {
239       /*
240       Completion routines expect the current irp stack location to be the same as when
241       IoSetCompletionRoutine was called to set them. A side effect is that completion
242       routines set by highest level drivers without their own stack location will receive
243       an invalid current stack location (at least it should be considered as invalid).
244       Since the DeviceObject argument passed is taken from the current stack, this value
245       is also invalid (NULL).
246       */
247       if (Irp->CurrentLocation < Irp->StackCount - 1)
248       {
249          IoSetPreviousIrpStackLocation(Irp);
250          DeviceObject = IoGetCurrentIrpStackLocation(Irp)->DeviceObject;
251       }
252       else
253       {
254          DeviceObject = NULL;
255       }
256
257       if (Irp->Stack[i].CompletionRoutine != NULL &&
258          ((NT_SUCCESS(Irp->IoStatus.Status) && (Irp->Stack[i].Control & SL_INVOKE_ON_SUCCESS)) ||
259          (!NT_SUCCESS(Irp->IoStatus.Status) && (Irp->Stack[i].Control & SL_INVOKE_ON_ERROR)) ||
260          (Irp->Cancel && (Irp->Stack[i].Control & SL_INVOKE_ON_CANCEL))))
261       {
262          Status = Irp->Stack[i].CompletionRoutine(DeviceObject,
263                                                   Irp,
264                                                   Irp->Stack[i].CompletionContext);
265
266          if (Status == STATUS_MORE_PROCESSING_REQUIRED)
267          {
268             return;
269          }
270       }
271    
272       if (IoGetCurrentIrpStackLocation(Irp)->Control & SL_PENDING_RETURNED)
273       {
274          Irp->PendingReturned = TRUE;
275       }
276    }
277
278    if (Irp->PendingReturned)
279      {
280         DPRINT("Dispatching APC\n");
281         KeInitializeApc(&Irp->Tail.Apc,
282                         &Irp->Tail.Overlay.Thread->Tcb,
283                         0,
284                         IopCompleteRequest,
285                         NULL,
286                         (PKNORMAL_ROUTINE)
287                         NULL,
288                         KernelMode,
289                         NULL);
290         KeInsertQueueApc(&Irp->Tail.Apc,
291                          (PVOID)Irp,
292                          (PVOID)(ULONG)PriorityBoost,
293                          KernelMode);
294         DPRINT("Finished dispatching APC\n");
295      }
296    else
297      {
298         DPRINT("Calling completion routine directly\n");
299         IoSecondStageCompletion(Irp,PriorityBoost);
300         DPRINT("Finished completition routine\n");
301      }
302 }
303
304
305 VOID STDCALL
306 IoCompleteRequest(PIRP Irp,
307                   CCHAR PriorityBoost)
308 {
309   IofCompleteRequest(Irp,
310                      PriorityBoost);
311 }
312
313
314 /**********************************************************************
315  * NAME                                                 EXPORTED
316  *      IoIsOperationSynchronous@4
317  *
318  * DESCRIPTION
319  *      Check if the I/O operation associated with the given IRP
320  *      is synchronous.
321  *
322  * ARGUMENTS
323  *      Irp     Packet to check.
324  *
325  * RETURN VALUE
326  *      TRUE if Irp's operation is synchronous; otherwise FALSE.
327  */
328 BOOLEAN STDCALL
329 IoIsOperationSynchronous(IN PIRP Irp)
330 {
331   PFILE_OBJECT FileObject = NULL;
332   ULONG Flags = 0;
333
334   /* Check the FILE_OBJECT's flags first. */
335   FileObject = IoGetCurrentIrpStackLocation(Irp)->FileObject;
336   if (!(FO_SYNCHRONOUS_IO & FileObject->Flags))
337     {
338       /* Check IRP's flags. */
339       Flags = Irp->Flags;
340       if (!((IRP_SYNCHRONOUS_API | IRP_SYNCHRONOUS_PAGING_IO) & Flags))
341         {
342           return(FALSE);
343         }
344     }
345
346   /* Check more IRP's flags. */
347   Flags = Irp->Flags;
348   if (!(IRP_PAGING_IO & Flags)
349       || (IRP_SYNCHRONOUS_PAGING_IO & Flags))
350     {
351       return(TRUE);
352     }
353
354   /* Otherwise, it is an asynchronous operation. */
355   return(FALSE);
356 }
357
358
359 VOID STDCALL
360 IoEnqueueIrp(IN PIRP Irp)
361 {
362   UNIMPLEMENTED;
363 }
364
365
366 VOID STDCALL
367 IoSetTopLevelIrp(IN PIRP Irp)
368 {
369   PETHREAD Thread;
370
371   Thread = PsGetCurrentThread();
372   Thread->TopLevelIrp->TopLevelIrp = Irp;
373 }
374
375
376 PIRP STDCALL
377 IoGetTopLevelIrp(VOID)
378 {
379   return(PsGetCurrentThread()->TopLevelIrp->TopLevelIrp);
380 }
381
382
383 VOID STDCALL
384 IoQueueThreadIrp(IN PIRP Irp)
385 {
386   UNIMPLEMENTED;
387 }
388
389 /*
390 NTSTATUS
391 STDCALL
392 IoSetDeviceInterfaceState(IN PUNICODE_STRING SymbolicLinkName, IN BOOLEAN Enable)
393 {
394   UNIMPLEMENTED;
395         return 0;
396 }
397
398 NTSTATUS
399 STDCALL
400 IoGetDeviceProperty(
401   IN PDEVICE_OBJECT DeviceObject,
402   IN DEVICE_REGISTRY_PROPERTY DeviceProperty,
403   IN ULONG BufferLength,
404   OUT PVOID PropertyBuffer,
405   OUT PULONG ResultLength)
406 {
407   UNIMPLEMENTED;
408         return 0;
409 }
410
411 NTSTATUS
412 STDCALL
413 IoOpenDeviceRegistryKey(
414   IN PDEVICE_OBJECT DeviceObject,
415   IN ULONG DevInstKeyType,
416   IN ACCESS_MASK DesiredAccess,
417   OUT PHANDLE DevInstRegKey)
418 {
419   UNIMPLEMENTED;
420         return 0;
421 }
422  */
423 /* EOF */