[irp] Move mini IRP handling into its own module
[people/sha0/winvblock.git] / src / bus / irp.c
1 /**
2  * Copyright (C) 2010, Shao Miller <shao.miller@yrdsb.edu.on.ca>.
3  *
4  * This file is part of WinVBlock, derived from WinAoE.
5  * For WinAoE contact information, see http://winaoe.org/
6  *
7  * WinVBlock is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * WinVBlock is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with WinVBlock.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 /**
22  * @file
23  *
24  * Handling IRPs
25  *
26  */
27
28 #include <ntddk.h>
29
30 #include "winvblock.h"
31 #include "portable.h"
32 #include "irp.h"
33 #include "driver.h"
34 #include "debug.h"
35
36 /*
37  * An internal type.  A device extension will have a
38  * pointer to this structure, but its type will be a void pointer
39  */
40 winvblock__def_struct ( handler_chain )
41 {
42   /*
43    * Points to an array of irp__handlings 
44    */
45   irp__handling *table;
46   /*
47    * Total table size, in bytes 
48    */
49   size_t size;
50   /*
51    * Points to the next table in the chain or NULL
52    */
53   handler_chain_ptr next;
54 };
55
56 /**
57  * Register an IRP handling table with a chain (with table size)
58  *
59  * @v chain_ptr Pointer to IRP handler chain to attach a table to
60  * @v table     Table to add
61  * @v size      Size of the table to add, in bytes
62  * @ret         FALSE for failure, TRUE for success
63  */
64 winvblock__lib_func winvblock__bool
65 irp__reg_table_s (
66   IN OUT irp__handler_chain_ptr chain_ptr,
67   IN irp__handling_ptr table,
68   IN size_t size
69  )
70 {
71   /*
72    * The type used by a device extension is opaque
73    */
74   handler_chain_ptr *link = ( handler_chain_ptr * ) chain_ptr,
75     new_link;
76
77   if ( link == NULL )
78     /*
79      * Nothing to attach to
80      */
81     return FALSE;
82   /*
83    * Allocate and attach a new link in the chain.
84    * Maybe we should use a spin-lock for this
85    */
86   new_link = ExAllocatePool ( NonPagedPool, sizeof ( handler_chain ) );
87   if ( new_link == NULL )
88     {
89       /*
90        * Really too bad
91        */
92       DBG ( "Could not allocate IRP handler chain!\n" );
93
94       return FALSE;
95     }
96   new_link->table = table;
97   /*
98    * Could sanity-check the size to be a multiple of sizeof(irp__handling)
99    */
100   new_link->size = size;
101   new_link->next = *link;
102   *link = new_link;
103   return TRUE;
104 }
105
106 /**
107  * Un-register an IRP handling table from a chain
108  *
109  * @v chain_ptr Pointer to IRP handler chain to remove table from
110  * @v table     Table to remove
111  * @ret         FALSE for failure, TRUE for success
112  */
113 winvblock__lib_func winvblock__bool
114 irp__new_chain (
115   IN OUT irp__handler_chain_ptr chain_ptr,
116   IN irp__handling_ptr table
117  )
118 {
119   winvblock__bool done = FALSE;
120   /*
121    * The type used by a device extension is opaque
122    */
123   handler_chain_ptr *link = ( handler_chain_ptr * ) chain_ptr;
124
125   if ( link == NULL )
126     /*
127      * No chain given
128      */
129     return FALSE;
130   /*
131    * Walk the chain, looking for the given table
132    */
133   while ( *link != NULL )
134     {
135       if ( link[0]->table == table )
136         {
137           /*
138            * Remove this link in the chain
139            */
140           handler_chain_ptr next = link[0]->next;
141           ExFreePool ( *link );
142           *link = next;
143           return TRUE;
144         }
145       link = &link[0]->next;
146     }
147
148   DBG ( "Table not found\n" );
149   return FALSE;
150 }
151
152 /**
153  * Mini IRP handling strategy
154  *
155  */
156 irp__handler_decl ( irp__process )
157 {
158   NTSTATUS status = STATUS_NOT_SUPPORTED;
159   size_t irp_handler_index;
160
161   /*
162    * Determine the device's IRP handler stack size
163    */
164   irp_handler_index = DeviceExtension->irp_handler_stack_size;
165
166   /*
167    * For each entry in the stack, in top-down order
168    */
169   while ( irp_handler_index-- )
170     {
171       irp__handling handling;
172       winvblock__bool handles_major,
173        handles_minor;
174
175       /*
176        * Get the handling entry
177        */
178       handling = DeviceExtension->irp_handler_stack_ptr[irp_handler_index];
179
180       handles_major = ( Stack->MajorFunction == handling.irp_major_func )
181         || handling.any_major;
182       handles_minor = ( Stack->MinorFunction == handling.irp_minor_func )
183         || handling.any_minor;
184       if ( handles_major && handles_minor )
185         status =
186           handling.handler ( DeviceObject, Irp, Stack, DeviceExtension,
187                              completion_ptr );
188       /*
189        * Do not process the IRP any further down the stack
190        */
191       if ( *completion_ptr )
192         break;
193     }
194
195   return status;
196 }