IofCallDriver(): Check for NULL MajorFunction handlers with KeBugCheck(0)
[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 }
78
79 #endif /* LIBCAPTIVE */
80
81 VOID STDCALL
82 IoInitializeIrp(PIRP Irp,
83                 USHORT PacketSize,
84                 CCHAR StackSize)
85 /*
86  * FUNCTION: Initalizes an irp allocated by the caller
87  * ARGUMENTS:
88  *          Irp = IRP to initalize
89  *          PacketSize = Size in bytes of the IRP
90  *          StackSize = Number of stack locations in the IRP
91  */
92 {
93   assert(Irp != NULL);
94
95   memset(Irp, 0, PacketSize);
96   Irp->Type = IO_TYPE_IRP;
97   Irp->Size = PacketSize;
98   Irp->StackCount = StackSize;
99   Irp->CurrentLocation = StackSize;
100   Irp->Tail.Overlay.CurrentStackLocation = &Irp->Stack[(ULONG)StackSize];
101 }
102
103
104 NTSTATUS FASTCALL
105 IofCallDriver(PDEVICE_OBJECT DeviceObject,
106               PIRP Irp)
107 /*
108   * FUNCTION: Sends an IRP to the next lower driver
109  */
110 {
111   NTSTATUS Status;
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   Param = IoGetNextIrpStackLocation(Irp);
125
126   DPRINT("IrpSp 0x%X\n", Param);
127   
128   Irp->Tail.Overlay.CurrentStackLocation--;
129   Irp->CurrentLocation--;
130   
131   DPRINT("MajorFunction %d\n", Param->MajorFunction);
132   DPRINT("DriverObject->MajorFunction[Param->MajorFunction] %x\n",
133          DriverObject->MajorFunction[Param->MajorFunction]);
134   if (!DriverObject->MajorFunction[Param->MajorFunction])
135     KeBugCheck(0);
136   Status = DriverObject->MajorFunction[Param->MajorFunction](DeviceObject,
137                                                              Irp);
138
139   return(Status);
140 }
141
142
143 NTSTATUS
144 STDCALL
145 IoCallDriver (PDEVICE_OBJECT DeviceObject, PIRP Irp)
146 {
147   return(IofCallDriver(DeviceObject,
148                        Irp));
149 }
150
151
152 PIRP STDCALL
153 IoAllocateIrp(CCHAR StackSize,
154               BOOLEAN ChargeQuota)
155 /*
156  * FUNCTION: Allocates an IRP
157  * ARGUMENTS:
158  *          StackSize = the size of the stack required for the irp
159  *          ChargeQuota = Charge allocation to current threads quota
160  * RETURNS: Irp allocated
161  */
162 {
163   PIRP Irp;
164
165 #if 0
166   DbgPrint("IoAllocateIrp(StackSize %d ChargeQuota %d)\n",
167            StackSize,
168            ChargeQuota);
169   KeDumpStackFrames(0,8);
170 #endif
171   
172   if (ChargeQuota)
173     {
174 //      Irp = ExAllocatePoolWithQuota(NonPagedPool,IoSizeOfIrp(StackSize));
175       Irp = ExAllocatePoolWithTag(NonPagedPool,
176                                   IoSizeOfIrp(StackSize),
177                                   TAG_IRP);
178     }
179   else
180     {
181       Irp = ExAllocatePoolWithTag(NonPagedPool,
182                                   IoSizeOfIrp(StackSize),
183                                   TAG_IRP);
184     }
185
186   if (Irp==NULL)
187     {
188       return(NULL);
189     }
190
191   IoInitializeIrp(Irp,
192                   IoSizeOfIrp(StackSize),
193                   StackSize);
194
195 //  DPRINT("Irp %x Irp->StackPtr %d\n", Irp, Irp->CurrentLocation);
196
197   return(Irp);
198 }
199
200 #ifndef LIBCAPTIVE
201
202 VOID STDCALL
203 IopCompleteRequest(struct _KAPC* Apc,
204                    PKNORMAL_ROUTINE* NormalRoutine,
205                    PVOID* NormalContext,
206                    PVOID* SystemArgument1,
207                    PVOID* SystemArgument2)
208 {
209   DPRINT("IopCompleteRequest(Apc %x, SystemArgument1 %x, (*SystemArgument1) %x\n",
210          Apc,
211          SystemArgument1,
212          *SystemArgument1);
213   IoSecondStageCompletion((PIRP)(*SystemArgument1),
214                           (KPRIORITY)(*SystemArgument2));
215 }
216
217 #endif /* LIBCAPTIVE */
218
219 VOID FASTCALL
220 IofCompleteRequest(PIRP Irp,
221                    CCHAR PriorityBoost)
222 /*
223  * FUNCTION: Indicates the caller has finished all processing for a given
224  * I/O request and is returning the given IRP to the I/O manager
225  * ARGUMENTS:
226  *         Irp = Irp to be cancelled
227  *         PriorityBoost = Increment by which to boost the priority of the
228  *                         thread making the request
229  */
230 {
231    int i;
232    NTSTATUS Status;
233    
234    DPRINT("IoCompleteRequest(Irp %x, PriorityBoost %d) Event %x THread %x\n",
235            Irp,PriorityBoost, Irp->UserEvent, PsGetCurrentThread());
236
237    for (i=Irp->CurrentLocation;i<(int)Irp->StackCount;i++)
238    {
239       if (Irp->Stack[i].CompletionRoutine != NULL)
240       {
241          Status = Irp->Stack[i].CompletionRoutine(
242                                              Irp->Stack[i].DeviceObject,
243                                              Irp,
244                                              Irp->Stack[i].CompletionContext);
245          if (Status == STATUS_MORE_PROCESSING_REQUIRED)
246          {
247             if (Irp->UserIosb)
248                {
249                   *Irp->UserIosb=Irp->IoStatus;
250                }
251             return;
252          }
253       }
254       if (Irp->Stack[i].Control & SL_PENDING_RETURNED)
255       {
256          Irp->PendingReturned = TRUE;
257       }
258       if (Irp->CurrentLocation < Irp->StackCount - 1)
259       {
260          IoSkipCurrentIrpStackLocation(Irp);
261       }
262    }
263    if (Irp->PendingReturned)
264      {
265         DPRINT("Dispatching APC\n");
266 #ifndef LIBCAPTIVE
267         KeInitializeApc(&Irp->Tail.Apc,
268                         &Irp->Tail.Overlay.Thread->Tcb,
269                         0,
270                         IopCompleteRequest,
271                         NULL,
272                         (PKNORMAL_ROUTINE)
273                         NULL,
274                         KernelMode,
275                         NULL);
276         KeInsertQueueApc(&Irp->Tail.Apc,
277                          (PVOID)Irp,
278                          (PVOID)(ULONG)PriorityBoost,
279                          KernelMode);
280         DPRINT("Finished dispatching APC\n");
281 #else /* !LIBCAPTIVE */
282         KeBugCheck(0);
283 #endif /* !LIBCAPTIVE */
284      }
285    else
286      {
287         DPRINT("Calling completion routine directly\n");
288         IoSecondStageCompletion(Irp,PriorityBoost);
289         DPRINT("Finished completition routine\n");
290      }
291 }
292
293
294 VOID STDCALL
295 IoCompleteRequest(PIRP Irp,
296                   CCHAR PriorityBoost)
297 {
298   IofCompleteRequest(Irp,
299                      PriorityBoost);
300 }
301
302
303 /**********************************************************************
304  * NAME                                                 EXPORTED
305  *      IoIsOperationSynchronous@4
306  *
307  * DESCRIPTION
308  *      Check if the I/O operation associated with the given IRP
309  *      is synchronous.
310  *
311  * ARGUMENTS
312  *      Irp     Packet to check.
313  *
314  * RETURN VALUE
315  *      TRUE if Irp's operation is synchronous; otherwise FALSE.
316  */
317 BOOLEAN STDCALL
318 IoIsOperationSynchronous(IN PIRP Irp)
319 {
320   PFILE_OBJECT FileObject = NULL;
321   ULONG Flags = 0;
322
323   /* Check the FILE_OBJECT's flags first. */
324   FileObject = IoGetCurrentIrpStackLocation(Irp)->FileObject;
325   if (!(FO_SYNCHRONOUS_IO & FileObject->Flags))
326     {
327       /* Check IRP's flags. */
328       Flags = Irp->Flags;
329       if (!((IRP_SYNCHRONOUS_API | IRP_SYNCHRONOUS_PAGING_IO) & Flags))
330         {
331 #ifdef LIBCAPTIVE
332           /* libcaptive is fully single-thread/single-process synchronous model. */
333           return TRUE;
334 #endif /* LIBCAPTIVE */
335           return(FALSE);
336         }
337     }
338
339   /* Check more IRP's flags. */
340   Flags = Irp->Flags;
341   if (!(IRP_PAGING_IO & Flags)
342       || (IRP_SYNCHRONOUS_PAGING_IO & Flags))
343     {
344       return(TRUE);
345     }
346
347   /* Otherwise, it is an asynchronous operation. */
348 #ifdef LIBCAPTIVE
349   /* libcaptive is fully single-thread/single-process synchronous model. */
350   return TRUE;
351 #endif /* LIBCAPTIVE */
352   return(FALSE);
353 }
354
355 #ifndef LIBCAPTIVE
356
357 VOID STDCALL
358 IoEnqueueIrp(IN PIRP Irp)
359 {
360   UNIMPLEMENTED;
361 }
362
363 #endif /* LIBCAPTIVE */
364
365 VOID STDCALL
366 IoSetTopLevelIrp(IN PIRP Irp)
367 {
368   PETHREAD Thread;
369
370   Thread = PsGetCurrentThread();
371   Thread->TopLevelIrp->TopLevelIrp = Irp;
372 }
373
374
375 PIRP STDCALL
376 IoGetTopLevelIrp(VOID)
377 {
378   return(PsGetCurrentThread()->TopLevelIrp->TopLevelIrp);
379 }
380
381 #ifndef LIBCAPTIVE
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
424 #endif /* LIBCAPTIVE */
425
426 /* EOF */