[IBBUS] workaround for some problems with WHQL PnP test over IPoIB. [mlnx: 3535]
[mirror/winof/.git] / core / complib / kernel / cl_pnp_po.c
1 /*\r
2  * Copyright (c) 2005 SilverStorm Technologies.  All rights reserved.\r
3  *\r
4  * This software is available to you under the OpenIB.org BSD license\r
5  * below:\r
6  *\r
7  *     Redistribution and use in source and binary forms, with or\r
8  *     without modification, are permitted provided that the following\r
9  *     conditions are met:\r
10  *\r
11  *      - Redistributions of source code must retain the above\r
12  *        copyright notice, this list of conditions and the following\r
13  *        disclaimer.\r
14  *\r
15  *      - Redistributions in binary form must reproduce the above\r
16  *        copyright notice, this list of conditions and the following\r
17  *        disclaimer in the documentation and/or other materials\r
18  *        provided with the distribution.\r
19  *\r
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
21  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
23  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
24  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
25  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
26  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
27  * SOFTWARE.\r
28  *\r
29  * $Id$\r
30  */\r
31 \r
32 \r
33 #include "complib/cl_pnp_po.h"\r
34 #include "complib/cl_debug.h"\r
35 #include "complib/cl_atomic.h"\r
36 \r
37 \r
38 static NTSTATUS\r
39 __start(\r
40         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
41         IN                              IRP* const                                      p_irp, \r
42                 OUT                     cl_irp_action_t* const          p_action );\r
43 \r
44 static NTSTATUS\r
45 __query_stop(\r
46         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
47         IN                              IRP* const                                      p_irp, \r
48                 OUT                     cl_irp_action_t* const          p_action );\r
49 \r
50 static NTSTATUS\r
51 __stop(\r
52         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
53         IN                              IRP* const                                      p_irp, \r
54                 OUT                     cl_irp_action_t* const          p_action );\r
55 \r
56 static NTSTATUS\r
57 __cancel_stop(\r
58         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
59         IN                              IRP* const                                      p_irp, \r
60                 OUT                     cl_irp_action_t* const          p_action );\r
61 \r
62 static NTSTATUS\r
63 __query_remove(\r
64         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
65         IN                              IRP* const                                      p_irp, \r
66                 OUT                     cl_irp_action_t* const          p_action );\r
67 \r
68 static NTSTATUS\r
69 __remove(\r
70         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
71         IN                              IRP* const                                      p_irp, \r
72                 OUT                     cl_irp_action_t* const          p_action );\r
73 \r
74 static NTSTATUS\r
75 __cancel_remove(\r
76         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
77         IN                              IRP* const                                      p_irp, \r
78                 OUT                     cl_irp_action_t* const          p_action );\r
79 \r
80 static NTSTATUS\r
81 __surprise_remove(\r
82         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
83         IN                              IRP* const                                      p_irp, \r
84                 OUT                     cl_irp_action_t* const          p_action );\r
85 \r
86 static NTSTATUS\r
87 __query_pnp_state(\r
88         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
89         IN                              IRP* const                                      p_irp, \r
90                 OUT                     cl_irp_action_t* const          p_action );\r
91 \r
92 static NTSTATUS\r
93 __device_usage_notification(\r
94         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
95         IN                              IRP* const                                      p_irp, \r
96                 OUT                     cl_irp_action_t* const          p_action );\r
97 \r
98 static NTSTATUS\r
99 __query_device_relations(\r
100         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
101         IN                              IRP* const                                      p_irp, \r
102                 OUT                     cl_irp_action_t* const          p_action );\r
103 \r
104 static NTSTATUS\r
105 __query_id(\r
106         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
107         IN                                      IRP* const                              p_irp, \r
108                 OUT                             cl_irp_action_t* const  p_action );\r
109 \r
110 static NTSTATUS\r
111 __query_device_text(\r
112         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
113         IN                              IRP* const                                      p_irp, \r
114                 OUT                     cl_irp_action_t* const          p_action );\r
115 \r
116 \r
117 /* All PnP code is called at passive, so it can all be paged out. */\r
118 #ifdef ALLOC_PRAGMA\r
119 #pragma alloc_text (PAGE, cl_init_pnp_po_ext)\r
120 #pragma alloc_text (PAGE, cl_pnp)\r
121 #pragma alloc_text (PAGE, __start)\r
122 #pragma alloc_text (PAGE, __query_stop)\r
123 #pragma alloc_text (PAGE, __stop)\r
124 #pragma alloc_text (PAGE, __cancel_stop)\r
125 #pragma alloc_text (PAGE, __query_remove)\r
126 #pragma alloc_text (PAGE, __remove)\r
127 #pragma alloc_text (PAGE, __cancel_remove)\r
128 #pragma alloc_text (PAGE, __surprise_remove)\r
129 #pragma alloc_text (PAGE, __query_pnp_state)\r
130 #pragma alloc_text (PAGE, __device_usage_notification)\r
131 #pragma alloc_text (PAGE, __query_device_relations)\r
132 #pragma alloc_text (PAGE, __query_id)\r
133 #pragma alloc_text (PAGE, __query_device_text)\r
134 #pragma alloc_text (PAGE, cl_do_sync_pnp)\r
135 #pragma alloc_text (PAGE_PNP, cl_irp_skip)\r
136 #pragma alloc_text (PAGE_PNP, cl_irp_complete)\r
137 #pragma alloc_text (PAGE_PNP, cl_irp_succeed)\r
138 #pragma alloc_text (PAGE_PNP, cl_irp_unsupported)\r
139 #endif\r
140 \r
141 \r
142 void\r
143 cl_init_pnp_po_ext(\r
144         IN      OUT                     DEVICE_OBJECT* const            p_dev_obj,\r
145         IN                              DEVICE_OBJECT* const            p_next_do,\r
146         IN                              DEVICE_OBJECT* const            p_pdo,\r
147         IN              const   uint32_t                                        pnp_po_dbg_lvl,\r
148         IN              const   cl_vfptr_pnp_po_t* const        vfptr_pnp_po,\r
149         IN              const   cl_vfptr_query_txt_t* const     vfptr_query_txt OPTIONAL )\r
150 {\r
151         cl_pnp_po_ext_t         *p_ext;\r
152 \r
153         CL_ENTER( CL_DBG_PNP, pnp_po_dbg_lvl );\r
154 \r
155         p_ext = p_dev_obj->DeviceExtension;\r
156 \r
157         p_ext->dbg_lvl = pnp_po_dbg_lvl;\r
158 \r
159         /* Store the pointer to our own device. */\r
160         p_ext->p_self_do = p_dev_obj;\r
161         IoInitializeRemoveLock( &p_ext->remove_lock, 'bilc', 15, 1000 );\r
162 \r
163         /* Initialize the PnP states. */\r
164         p_ext->pnp_state = NotStarted;\r
165         p_ext->last_pnp_state = NotStarted;\r
166 \r
167         /* Store the pointer to the next device in the stack. */\r
168         p_ext->p_next_do = p_next_do;\r
169 \r
170         /* Store the pointer to the underlying PDO. */\r
171         p_ext->p_pdo = p_pdo;\r
172 \r
173         /* Store the PnP virtual function pointer table. */\r
174         p_ext->vfptr_pnp_po = vfptr_pnp_po;\r
175 \r
176         /* Store the Power Management virtual function pointer table. */\r
177         p_ext->vfptr_query_txt = vfptr_query_txt;\r
178 \r
179         /*\r
180          * Mark power routines as pageable.  This changes when the device is\r
181          * notified of being in the paging path.\r
182          */\r
183         p_dev_obj->Flags |= DO_POWER_PAGABLE;\r
184 \r
185         /* Clear the initializing flag before returning. */\r
186         p_dev_obj->Flags &= ~DO_DEVICE_INITIALIZING;\r
187 \r
188         CL_EXIT( CL_DBG_PNP, p_ext->dbg_lvl );\r
189 }\r
190 \r
191 \r
192 NTSTATUS\r
193 cl_pnp(\r
194         IN                              PDEVICE_OBJECT                          p_dev_obj,\r
195         IN                              PIRP                                            p_irp )\r
196 {\r
197         NTSTATUS                        status;\r
198         IO_STACK_LOCATION       *p_io_stack;\r
199         cl_pnp_po_ext_t         *p_ext;\r
200         cl_irp_action_t         action;\r
201 \r
202         p_ext = p_dev_obj->DeviceExtension;\r
203 \r
204         CL_ENTER( CL_DBG_PNP, p_ext->dbg_lvl );\r
205 \r
206         CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, \r
207                 ("PDO %p, ext %p\n",  p_dev_obj, p_ext) );\r
208 \r
209         CL_ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );\r
210         \r
211         status = IoAcquireRemoveLock( &p_ext->remove_lock, p_irp );\r
212         if( !NT_SUCCESS( status ) )\r
213         {\r
214                 CL_TRACE_EXIT( CL_DBG_ERROR, p_ext->dbg_lvl, \r
215                         ("IoAcquireRemoveLock returned %08x.\n", status) );\r
216                 p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
217                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, \r
218                         ("Minor function %x for %s\n", p_io_stack->MinorFunction, p_ext->vfptr_pnp_po->identity) );\r
219                 p_irp->IoStatus.Status = status;\r
220                 IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
221                 return status;\r
222         }\r
223 \r
224         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
225         ASSERT( p_io_stack->MajorFunction == IRP_MJ_PNP );\r
226 \r
227         switch( p_io_stack->MinorFunction )\r
228         {\r
229         case IRP_MN_START_DEVICE:\r
230                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, \r
231                         ("IRP_MN_START_DEVICE for %s\n", p_ext->vfptr_pnp_po->identity) );\r
232                 status = __start( p_dev_obj, p_irp, &action );\r
233                 break;\r
234 \r
235         case IRP_MN_QUERY_STOP_DEVICE:\r
236                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("IRP_MN_QUERY_STOP_DEVICE for %s\n", \r
237                         p_ext->vfptr_pnp_po->identity) );\r
238                 status = __query_stop( p_dev_obj, p_irp, &action );\r
239                 break;\r
240 \r
241         case IRP_MN_STOP_DEVICE:\r
242                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, \r
243                         ("IRP_MN_STOP_DEVICE for %s\n", p_ext->vfptr_pnp_po->identity) );\r
244                 status = __stop( p_dev_obj, p_irp, &action );\r
245                 break;\r
246 \r
247         case IRP_MN_CANCEL_STOP_DEVICE:\r
248                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, \r
249                         ("IRP_MN_CANCEL_STOP_DEVICE for %s\n", p_ext->vfptr_pnp_po->identity) );\r
250                 status = __cancel_stop( p_dev_obj, p_irp, &action );\r
251                 break;\r
252 \r
253         case IRP_MN_QUERY_REMOVE_DEVICE:\r
254                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, \r
255                         ("IRP_MN_QUERY_REMOVE_DEVICE for %s\n",\r
256                         p_ext->vfptr_pnp_po->identity) );\r
257                 status = __query_remove( p_dev_obj, p_irp, &action );\r
258                 break;\r
259 \r
260         case IRP_MN_REMOVE_DEVICE:\r
261                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, \r
262                         ("IRP_MN_REMOVE_DEVICE for %s\n", p_ext->vfptr_pnp_po->identity) );\r
263                 status = __remove( p_dev_obj, p_irp, &action );\r
264                 break;\r
265 \r
266         case IRP_MN_CANCEL_REMOVE_DEVICE:\r
267                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, \r
268                         ("IRP_MN_CANCEL_REMOVE_DEVICE for %s\n",\r
269                         p_ext->vfptr_pnp_po->identity) );\r
270                 status = __cancel_remove( p_dev_obj, p_irp, &action );\r
271                 break;\r
272 \r
273         case IRP_MN_SURPRISE_REMOVAL:\r
274                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("IRP_MN_SURPRISE_REMOVAL for %s\n",\r
275                         p_ext->vfptr_pnp_po->identity) );\r
276                 status = __surprise_remove( p_dev_obj, p_irp, &action );\r
277                 break;\r
278 \r
279         case IRP_MN_QUERY_CAPABILITIES:\r
280                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, \r
281                         ("IRP_MN_QUERY_CAPABILITIES for %s\n",\r
282                         p_ext->vfptr_pnp_po->identity) );\r
283                 status = p_ext->vfptr_pnp_po->pfn_query_capabilities( \r
284                         p_dev_obj, p_irp, &action );\r
285                 break;\r
286 \r
287         case IRP_MN_QUERY_PNP_DEVICE_STATE:\r
288                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, \r
289                         ("IRP_MN_QUERY_PNP_DEVICE_STATE for %s\n", \r
290                         p_ext->vfptr_pnp_po->identity) );\r
291                 status = __query_pnp_state( p_dev_obj, p_irp, &action );\r
292                 break;\r
293 \r
294         case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:\r
295                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl,\r
296                         ("IRP_MN_FILTER_RESOURCE_REQUIREMENTS for %s\n", \r
297                         p_ext->vfptr_pnp_po->identity) );\r
298                 status = p_ext->vfptr_pnp_po->pfn_filter_res_req( \r
299                         p_dev_obj, p_irp, &action );\r
300                 break;\r
301 \r
302         case IRP_MN_DEVICE_USAGE_NOTIFICATION:\r
303                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, \r
304                         ("IRP_MN_DEVICE_USAGE_NOTIFICATION for %s\n",\r
305                         p_ext->vfptr_pnp_po->identity) );\r
306                 status = __device_usage_notification( p_dev_obj, p_irp, &action );\r
307                 break;\r
308 \r
309         case IRP_MN_QUERY_DEVICE_RELATIONS:\r
310                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, \r
311                         ("IRP_MN_QUERY_DEVICE_RELATIONS for %s\n", \r
312                         p_ext->vfptr_pnp_po->identity) );\r
313                 status = __query_device_relations( p_dev_obj, p_irp, &action );\r
314                 break;\r
315 \r
316         case IRP_MN_QUERY_RESOURCES:\r
317                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("IRP_MN_QUERY_RESOURCES for %s\n",\r
318                         p_ext->vfptr_pnp_po->identity) );\r
319                 status = p_ext->vfptr_pnp_po->pfn_query_resources( \r
320                         p_dev_obj, p_irp, &action );\r
321                 break;\r
322 \r
323         case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:\r
324                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl,\r
325                         ("IRP_MN_QUERY_RESOURCE_REQUIREMENTS for %s\n",\r
326                         p_ext->vfptr_pnp_po->identity) );\r
327                 status = p_ext->vfptr_pnp_po->pfn_query_res_req( \r
328                         p_dev_obj, p_irp, &action );\r
329                 break;\r
330 \r
331         case IRP_MN_QUERY_ID:\r
332                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, \r
333                         ("IRP_MN_QUERY_ID for %s\n", p_ext->vfptr_pnp_po->identity) );\r
334                 status = __query_id( p_dev_obj, p_irp, &action );\r
335                 break;\r
336 \r
337         case IRP_MN_QUERY_DEVICE_TEXT:\r
338                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl,\r
339                         ("IRP_MN_QUERY_DEVICE_TEXT for %s\n", \r
340                         p_ext->vfptr_pnp_po->identity) );\r
341                 status = __query_device_text( p_dev_obj, p_irp, &action );\r
342                 break;\r
343 \r
344         case IRP_MN_QUERY_BUS_INFORMATION:\r
345                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, \r
346                         ("IRP_MN_QUERY_BUS_INFORMATION for %s\n", \r
347                         p_ext->vfptr_pnp_po->identity) );\r
348                 status = p_ext->vfptr_pnp_po->pfn_query_bus_info( \r
349                         p_dev_obj, p_irp, &action );\r
350                 break;\r
351 \r
352         case IRP_MN_QUERY_INTERFACE:\r
353                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("IRP_MN_QUERY_INTERFACE for %s\n",\r
354                         p_ext->vfptr_pnp_po->identity) );\r
355                 status = p_ext->vfptr_pnp_po->pfn_query_interface( \r
356                         p_dev_obj, p_irp, &action );\r
357                 break;\r
358 \r
359         case IRP_MN_READ_CONFIG:\r
360                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl,\r
361                         ("IRP_MN_READ_CONFIG for %s\n", p_ext->vfptr_pnp_po->identity) );\r
362                 status = p_ext->vfptr_pnp_po->pfn_read_config(\r
363                         p_dev_obj, p_irp, &action );\r
364                 break;\r
365 \r
366         case IRP_MN_WRITE_CONFIG:\r
367                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl,\r
368                         ("IRP_MN_WRITE_CONFIG for %s\n", p_ext->vfptr_pnp_po->identity) );\r
369                 status = p_ext->vfptr_pnp_po->pfn_write_config( \r
370                         p_dev_obj, p_irp, &action );\r
371                 break;\r
372 \r
373         case IRP_MN_EJECT:\r
374                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl,\r
375                         ("IRP_MN_EJECT for %s\n", p_ext->vfptr_pnp_po->identity) );\r
376                 status = p_ext->vfptr_pnp_po->pfn_eject( \r
377                         p_dev_obj, p_irp, &action );\r
378                 break;\r
379 \r
380         case IRP_MN_SET_LOCK:\r
381                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl,\r
382                         ("IRP_MN_SET_LOCK for %s\n", p_ext->vfptr_pnp_po->identity) );\r
383                 status = p_ext->vfptr_pnp_po->pfn_set_lock( \r
384                         p_dev_obj, p_irp, &action );\r
385                 break;\r
386 \r
387         default:\r
388                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, \r
389                         ("Unknown IRP minor function 0x%x for %s\n", \r
390                         p_io_stack->MinorFunction, p_ext->vfptr_pnp_po->identity) );\r
391                 status = p_ext->vfptr_pnp_po->pfn_unknown(\r
392                         p_dev_obj, p_irp, &action );\r
393                 break;\r
394         }\r
395 \r
396         switch( action )\r
397         {\r
398         case IrpPassDown:\r
399                 p_irp->IoStatus.Status = status;\r
400                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("IrpPassDown: passing down to PDO %p, ext %p, status %#x\n",\r
401                         p_ext->p_next_do, p_ext, p_irp->IoStatus.Status) );\r
402                 IoCopyCurrentIrpStackLocationToNext( p_irp );\r
403                 status = IoCallDriver( p_ext->p_next_do, p_irp );\r
404                 break;\r
405 \r
406         case IrpSkip:\r
407                 p_irp->IoStatus.Status = status;\r
408 \r
409         case IrpIgnore:\r
410                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("IrpSkip/IrpIgnore: skipping down to PDO %p, ext %p, status %#x\n",\r
411                         p_ext->p_next_do, p_ext, p_irp->IoStatus.Status) );\r
412                 IoSkipCurrentIrpStackLocation( p_irp );\r
413                 status = IoCallDriver( p_ext->p_next_do, p_irp );\r
414                 break;\r
415 \r
416         case IrpComplete:\r
417                 p_irp->IoStatus.Status = status;\r
418                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("IrpComplete: complete IRP with status %#x\n",\r
419                         p_irp->IoStatus.Status) );\r
420                 IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
421                 break;\r
422 \r
423         case IrpDoNothing:\r
424                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("IrpDoNothing: do nothing\n") );\r
425                 break;\r
426         }\r
427 \r
428         if( action != IrpDoNothing )\r
429                 IoReleaseRemoveLock( &p_ext->remove_lock, p_irp );\r
430 \r
431         CL_TRACE_EXIT( CL_DBG_PNP, p_ext->dbg_lvl, ("returned with status %#x\n", status) );\r
432         return status;\r
433 }\r
434 \r
435 \r
436 static NTSTATUS\r
437 __start(\r
438         IN                              DEVICE_OBJECT* const    p_dev_obj,\r
439         IN                              IRP* const                              p_irp, \r
440                 OUT                     cl_irp_action_t* const  p_action )\r
441 {\r
442         cl_pnp_po_ext_t *p_ext;\r
443         NTSTATUS                        status;\r
444 \r
445         p_ext = p_dev_obj->DeviceExtension;\r
446 \r
447         CL_ENTER( CL_DBG_PNP, p_ext->dbg_lvl );\r
448 \r
449         status = p_ext->vfptr_pnp_po->pfn_start( p_dev_obj, p_irp, p_action );\r
450         if( NT_SUCCESS( status ) )\r
451                 cl_set_pnp_state( p_ext, Started );\r
452 \r
453         /*\r
454          * If we get the start request when we're already started, don't \r
455          * re-initialize the stop lock.\r
456          */\r
457         if( p_ext->last_pnp_state != Started ) {\r
458                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("IoInitializeRemoveLock: stop_lock %p[\n", &p_ext->stop_lock));\r
459                 IoInitializeRemoveLock( &p_ext->stop_lock, 'dtci', 0, 1000 );\r
460         }\r
461 \r
462         CL_EXIT( CL_DBG_PNP, p_ext->dbg_lvl );\r
463         return status;\r
464 }\r
465 \r
466 \r
467 static NTSTATUS\r
468 __query_stop(\r
469         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
470         IN                              IRP* const                                      p_irp, \r
471                 OUT                     cl_irp_action_t* const          p_action )\r
472 {\r
473         cl_pnp_po_ext_t *p_ext;\r
474         NTSTATUS                        status;\r
475 \r
476         p_ext = p_dev_obj->DeviceExtension;\r
477 \r
478         CL_ENTER( CL_DBG_PNP, p_ext->dbg_lvl );\r
479 \r
480         /* \r
481          * We must fail the query if there are any paging, dump, or hibernation \r
482          * files on the device.\r
483          */\r
484         if( p_ext->n_crash_files || \r
485                 p_ext->n_hibernate_files || \r
486                 p_ext->n_paging_files )\r
487         {\r
488                 *p_action = IrpComplete;\r
489                 /* Fail the request. */\r
490                 CL_TRACE_EXIT( CL_DBG_PNP, p_ext->dbg_lvl, \r
491                         ("Failing IRP_MN_QUERY_STOP_DEVICE - device %s has:\n"\r
492                         "\t\t%d paging files\n\t\t%d crash files\n"\r
493                         "\t\t%d hibernate files\n", p_ext->vfptr_pnp_po->identity,\r
494                         p_ext->n_paging_files, p_ext->n_crash_files, \r
495                         p_ext->n_hibernate_files) );\r
496                 return STATUS_UNSUCCESSFUL;\r
497         }\r
498 \r
499         /* \r
500          * Mark the device as stop pending so that all new non-_PnP and non-_Power\r
501          * IRPs get queued or failed.\r
502          */\r
503         cl_set_pnp_state( p_ext, StopPending );\r
504 \r
505         if( p_ext->last_pnp_state == Started )\r
506         {\r
507                 /* Acquire the lock so we can release and wait. */\r
508                 status = IoAcquireRemoveLock( &p_ext->stop_lock, p_irp );\r
509                 if( !NT_SUCCESS( status ) )\r
510                 {\r
511                         CL_TRACE( CL_DBG_ERROR, p_ext->dbg_lvl, \r
512                                 ("IoAcquireRemoveLock returned %08x. Continue anyway ...\n", status) );\r
513                 }\r
514                 /* Wait for all IO operations to complete. */\r
515                 IoReleaseRemoveLockAndWait( &p_ext->stop_lock, p_irp );\r
516         }\r
517 \r
518         status = p_ext->vfptr_pnp_po->pfn_query_stop( p_dev_obj, p_irp, p_action );\r
519         CL_EXIT( CL_DBG_PNP, p_ext->dbg_lvl );\r
520         return status;\r
521 }\r
522 \r
523 \r
524 static NTSTATUS\r
525 __stop(\r
526         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
527         IN                              IRP* const                                      p_irp, \r
528                 OUT                     cl_irp_action_t* const          p_action )\r
529 {\r
530         NTSTATUS                        status;\r
531         cl_pnp_po_ext_t *p_ext;\r
532 \r
533         p_ext = p_dev_obj->DeviceExtension;\r
534 \r
535         CL_ENTER( CL_DBG_PNP, p_ext->dbg_lvl );\r
536 \r
537         ASSERT( p_ext->pnp_state == StopPending );\r
538 \r
539         cl_set_pnp_state( p_ext, Stopped );\r
540 \r
541         status = p_ext->vfptr_pnp_po->pfn_stop( p_dev_obj, p_irp, p_action );\r
542 \r
543         /* Release resources. */\r
544         if( p_ext->vfptr_pnp_po->pfn_release_resources )\r
545                 p_ext->vfptr_pnp_po->pfn_release_resources( p_dev_obj );\r
546 \r
547         CL_EXIT( CL_DBG_PNP, p_ext->dbg_lvl );\r
548         return status;\r
549 }\r
550 \r
551 \r
552 static NTSTATUS\r
553 __cancel_stop(\r
554         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
555         IN                              IRP* const                                      p_irp, \r
556                 OUT                     cl_irp_action_t* const          p_action )\r
557 {\r
558         cl_pnp_po_ext_t*        p_ext;\r
559         NTSTATUS                        status;\r
560 \r
561         p_ext = p_dev_obj->DeviceExtension;\r
562 \r
563         CL_ENTER( CL_DBG_PNP, p_ext->dbg_lvl );\r
564 \r
565         /* Call the device specific handler. */\r
566         status = p_ext->vfptr_pnp_po->pfn_cancel_stop( p_dev_obj, p_irp, p_action );\r
567         ASSERT( NT_SUCCESS(status) );\r
568 \r
569         /* \r
570          * If we were never stopped (a higher level driver failed the \r
571          * IRP_MN_QUERY_STOP but passed down the cancel), just return.\r
572          */\r
573         if( p_ext->pnp_state != StopPending )\r
574         {\r
575                 CL_TRACE_EXIT( CL_DBG_PNP, p_ext->dbg_lvl,\r
576                         ("IRP_MN_CANCEL_STOP_DEVICE received in invalid state.\n") );\r
577                 return status;\r
578         }\r
579 \r
580         if( p_ext->last_pnp_state == Started )\r
581         {\r
582                 /*\r
583                  * Re-initialize the stop lock before rolling back the PnP\r
584                  * state so that there's no contention while it's uninitialized.\r
585                  */\r
586                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("IoInitializeRemoveLock: stop_lock %p[\n", &p_ext->stop_lock));\r
587                 IoInitializeRemoveLock( &p_ext->stop_lock, 'dtci', 0, 1000 );\r
588 #if 0           \r
589                 // leo: it seems like a bug, because it can never get released\r
590                 {\r
591                 /* \r
592                  * Acquire the stop lock to allow releasing and waiting when stopping.\r
593                  */\r
594                         NTSTATUS                        status1;\r
595                         CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("IoAcquireRemoveLock: stop_lock %p[\n", &p_ext->stop_lock));\r
596                         status1 = IoAcquireRemoveLock( &p_ext->stop_lock, NULL );\r
597                         if( !NT_SUCCESS( status1 ) )\r
598                         {\r
599                                 CL_TRACE( CL_DBG_ERROR, p_ext->dbg_lvl, \r
600                                         ("IoAcquireRemoveLock returned %08x. Continue anyway ...\n", status) );\r
601                         }\r
602                         CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("IoAcquireRemoveLock: stop_lock ]\n"));\r
603                 }\r
604 #endif          \r
605         }\r
606 \r
607         /* Return to the previous PnP state. */\r
608         cl_rollback_pnp_state( p_ext );\r
609 \r
610         CL_EXIT( CL_DBG_PNP, p_ext->dbg_lvl );\r
611         return status;\r
612 }\r
613 \r
614 \r
615 static NTSTATUS\r
616 __query_remove(\r
617         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
618         IN                              IRP* const                                      p_irp, \r
619                 OUT                     cl_irp_action_t* const          p_action )\r
620 {\r
621         cl_pnp_po_ext_t *p_ext;\r
622         NTSTATUS                        status;\r
623 \r
624         p_ext = p_dev_obj->DeviceExtension;\r
625 \r
626         CL_ENTER( CL_DBG_PNP, p_ext->dbg_lvl );\r
627 \r
628         /*\r
629          * We must fail the query if there are any paging, dump, or hibernation\r
630          * files on the device.\r
631          */\r
632         if( p_ext->n_crash_files || \r
633                 p_ext->n_hibernate_files || \r
634                 p_ext->n_paging_files )\r
635         {\r
636                 *p_action = IrpComplete;\r
637                 /* Fail the request. */\r
638                 CL_TRACE_EXIT( CL_DBG_PNP, p_ext->dbg_lvl, \r
639                         ("Failing IRP_MN_QUERY_REMOVE_DEVICE - device has:\n"\r
640                         "\t\t%d paging files\n\t\t%d crash files\n"\r
641                         "\t\t%d hibernate files\n", p_ext->n_paging_files,\r
642                         p_ext->n_crash_files, p_ext->n_hibernate_files) );\r
643                 return STATUS_UNSUCCESSFUL;\r
644         }\r
645 \r
646         /* We fail the query if we have any interface outstanding. */\r
647         if( p_ext->n_ifc_ref )\r
648         {\r
649                 *p_action = IrpComplete;\r
650                 CL_TRACE_EXIT( CL_DBG_PNP, p_ext->dbg_lvl,\r
651                         ("Failing IRP_MN_QUERY_REMOVE_DEVICE - interface ref count: %d\n",\r
652                         p_ext->n_ifc_ref) );\r
653                 return STATUS_UNSUCCESSFUL;\r
654         }\r
655 \r
656         /*\r
657          * Mark the device as remove pending so that all new non-PnP and \r
658          * non-Power IRPs get queued or failed.\r
659          */\r
660         cl_set_pnp_state( p_ext, RemovePending );\r
661 \r
662         /* Call type specific handler. */\r
663         status = \r
664                 p_ext->vfptr_pnp_po->pfn_query_remove( p_dev_obj, p_irp, p_action );\r
665 \r
666         CL_EXIT( CL_DBG_PNP, p_ext->dbg_lvl );\r
667         return status;\r
668 }\r
669 \r
670 \r
671 static NTSTATUS\r
672 __remove(\r
673         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
674         IN                              IRP* const                                      p_irp, \r
675                 OUT                     cl_irp_action_t* const          p_action )\r
676 {\r
677         NTSTATUS                        status;\r
678         cl_pnp_po_ext_t *p_ext;\r
679 \r
680         p_ext = p_dev_obj->DeviceExtension;\r
681 \r
682         CL_ENTER( CL_DBG_PNP, p_ext->dbg_lvl );\r
683 \r
684         ASSERT( p_ext->pnp_state == NotStarted ||\r
685                 p_ext->pnp_state == Started ||\r
686                 p_ext->pnp_state == RemovePending ||\r
687                 p_ext->pnp_state == SurpriseRemoved ||\r
688                 // it can be on this state if IRP_MN_START_DEVICE failed\r
689                 // pnpdtest /rebalance FailRestart creates this situation\r
690                 p_ext->pnp_state == Stopped);\r
691 \r
692         /* Set the device state. */\r
693         cl_set_pnp_state( p_ext, Deleted );\r
694 \r
695         status = p_ext->vfptr_pnp_po->pfn_remove( p_dev_obj, p_irp, p_action );\r
696 \r
697         CL_EXIT( CL_DBG_PNP, p_ext->dbg_lvl );\r
698         return status;\r
699 }\r
700 \r
701 \r
702 NTSTATUS\r
703 cl_do_remove(\r
704         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
705         IN                              IRP* const                                      p_irp, \r
706                 OUT                     cl_irp_action_t* const          p_action )\r
707 {\r
708         NTSTATUS                        status;\r
709         cl_pnp_po_ext_t *p_ext;\r
710 \r
711         p_ext = p_dev_obj->DeviceExtension;\r
712 \r
713         CL_ENTER( CL_DBG_PNP, p_ext->dbg_lvl );\r
714 \r
715         /* Wait for all I/O operations to complete. */\r
716         IoReleaseRemoveLockAndWait( &p_ext->remove_lock, p_irp );\r
717 \r
718         /* Release resources if it was not done yet. */\r
719         if( p_ext->last_pnp_state != SurpriseRemoved &&\r
720                 p_ext->last_pnp_state != Stopped && \r
721                 p_ext->vfptr_pnp_po->pfn_release_resources )\r
722         {\r
723                 p_ext->vfptr_pnp_po->pfn_release_resources( p_dev_obj );\r
724         }\r
725 \r
726         /* Set the IRP status. */\r
727         p_irp->IoStatus.Status = STATUS_SUCCESS;\r
728 \r
729         /* Pass the IRP down. */\r
730         IoSkipCurrentIrpStackLocation( p_irp );\r
731         status = IoCallDriver( p_ext->p_next_do, p_irp );\r
732         *p_action = IrpDoNothing;\r
733 \r
734         /* Detach and destroy the device. */\r
735         IoDetachDevice( p_ext->p_next_do );\r
736         IoDeleteDevice( p_dev_obj );\r
737 \r
738         CL_EXIT( CL_DBG_PNP, p_ext->dbg_lvl );\r
739         return status;\r
740 }\r
741 \r
742 \r
743 static NTSTATUS\r
744 __cancel_remove(\r
745         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
746         IN                              IRP* const                                      p_irp, \r
747                 OUT                     cl_irp_action_t* const          p_action )\r
748 {\r
749         cl_pnp_po_ext_t *p_ext;\r
750         NTSTATUS                        status;\r
751 \r
752         p_ext = p_dev_obj->DeviceExtension;\r
753 \r
754         CL_ENTER( CL_DBG_PNP, p_ext->dbg_lvl );\r
755 \r
756         status = \r
757                 p_ext->vfptr_pnp_po->pfn_cancel_remove( p_dev_obj, p_irp, p_action );\r
758         ASSERT( NT_SUCCESS(status) );\r
759 \r
760         if( p_ext->pnp_state != RemovePending )\r
761         {\r
762                 CL_TRACE_EXIT( CL_DBG_PNP, p_ext->dbg_lvl, \r
763                         ("IRP_MN_CANCEL_REMOVE_DEVICE received in invalid state.\n") );\r
764                 return status;\r
765         }\r
766 \r
767         cl_rollback_pnp_state( p_ext );\r
768 \r
769         CL_EXIT( CL_DBG_PNP, p_ext->dbg_lvl );\r
770         return status;\r
771 }\r
772 \r
773 \r
774 static NTSTATUS\r
775 __surprise_remove(\r
776         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
777         IN                              IRP* const                                      p_irp, \r
778                 OUT                     cl_irp_action_t* const          p_action )\r
779 {\r
780         NTSTATUS                        status;\r
781         cl_pnp_po_ext_t *p_ext;\r
782 \r
783         p_ext = p_dev_obj->DeviceExtension;\r
784 \r
785         CL_ENTER( CL_DBG_PNP, p_ext->dbg_lvl );\r
786 \r
787         cl_set_pnp_state( p_ext, SurpriseRemoved );\r
788 \r
789         /* Call handler before releasing resources. */\r
790         status = \r
791                 p_ext->vfptr_pnp_po->pfn_surprise_remove( p_dev_obj, p_irp, p_action );\r
792 \r
793         /* Release resources. */\r
794         if( p_ext->last_pnp_state != Stopped &&\r
795                 p_ext->vfptr_pnp_po->pfn_release_resources )\r
796         {\r
797                 p_ext->vfptr_pnp_po->pfn_release_resources( p_dev_obj );\r
798         }\r
799 \r
800         CL_EXIT( CL_DBG_PNP, p_ext->dbg_lvl );\r
801         return status;\r
802 }\r
803 \r
804 \r
805 static NTSTATUS\r
806 __query_pnp_state(\r
807         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
808         IN                              IRP* const                                      p_irp, \r
809                 OUT                     cl_irp_action_t* const          p_action )\r
810 {\r
811         cl_pnp_po_ext_t *p_ext;\r
812         NTSTATUS                        status;\r
813 \r
814         p_ext = p_dev_obj->DeviceExtension;\r
815 \r
816         CL_ENTER( CL_DBG_PNP, p_ext->dbg_lvl );\r
817 \r
818         /* \r
819          * Flag the device as not removable if there are any special files on it.\r
820          */\r
821         if( p_ext->n_paging_files || \r
822                 p_ext->n_crash_files || \r
823                 p_ext->n_hibernate_files )\r
824         {\r
825                 p_irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE;\r
826         }\r
827 \r
828         status = \r
829                 p_ext->vfptr_pnp_po->pfn_query_pnp_state( p_dev_obj, p_irp, p_action );\r
830         CL_EXIT( CL_DBG_PNP, p_ext->dbg_lvl );\r
831         return status;\r
832 }\r
833 \r
834 \r
835 static inline void\r
836 __lock_po_code(\r
837         IN      OUT                     cl_pnp_po_ext_t* const          p_ext )\r
838 {\r
839         if( !p_ext->h_cl_locked_section )\r
840         {\r
841                 /*\r
842                  * No handle exists.  This is the first lock.  Once locked, the\r
843                  * handle is valid as long as the driver is loaded.  Lock any \r
844                  * function in the PAGE_PNP section.\r
845                  */\r
846 #pragma warning( push, 3 )\r
847                 p_ext->h_cl_locked_section = MmLockPagableCodeSection( cl_power );\r
848                 /* TODO: Pick first non-CL function */\r
849                 p_ext->h_user_locked_section = MmLockPagableCodeSection( \r
850                         p_ext->vfptr_pnp_po->pfn_set_power );\r
851 #pragma warning( pop )\r
852         }\r
853         else\r
854         {\r
855                 /* Handle already exists.  Locking by handle is faster. */\r
856                 MmLockPagableSectionByHandle( p_ext->h_cl_locked_section );\r
857                 if( p_ext->h_user_locked_section )\r
858                         MmLockPagableSectionByHandle( p_ext->h_user_locked_section );\r
859         }\r
860 }\r
861 \r
862 \r
863 static inline void\r
864 __unlock_po_code(\r
865         IN      OUT                     cl_pnp_po_ext_t* const          p_ext )\r
866 {\r
867         ASSERT( p_ext->h_cl_locked_section );\r
868         MmUnlockPagableImageSection( p_ext->h_cl_locked_section );\r
869         if( p_ext->h_user_locked_section )\r
870                 MmUnlockPagableImageSection( p_ext->h_user_locked_section );\r
871 }\r
872 \r
873 \r
874 static NTSTATUS\r
875 __device_usage_notification(\r
876         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
877         IN                              IRP* const                                      p_irp, \r
878                 OUT                     cl_irp_action_t* const          p_action )\r
879 {\r
880         cl_pnp_po_ext_t         *p_ext;\r
881         IO_STACK_LOCATION       *p_io_stack;\r
882         atomic32_t                      *p_val;\r
883         NTSTATUS                        status;\r
884 \r
885         p_ext = p_dev_obj->DeviceExtension;\r
886 \r
887         CL_ENTER( CL_DBG_PNP, p_ext->dbg_lvl );\r
888         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
889 \r
890         switch( p_io_stack->Parameters.UsageNotification.Type )\r
891         {\r
892         case DeviceUsageTypePaging:\r
893                 p_val = &p_ext->n_paging_files;\r
894                 break;\r
895 \r
896         case DeviceUsageTypeDumpFile:\r
897                 p_val = &p_ext->n_crash_files;\r
898                 break;\r
899 \r
900         case DeviceUsageTypeHibernation:\r
901                 p_val = &p_ext->n_hibernate_files;\r
902                 break;\r
903 \r
904         default:\r
905                 CL_TRACE_EXIT( CL_DBG_ERROR, p_ext->dbg_lvl, \r
906                         ("Invalid notification type.\n") );\r
907                 return STATUS_INVALID_PARAMETER;\r
908         }\r
909 \r
910         if( p_io_stack->Parameters.UsageNotification.InPath )\r
911         {\r
912                 cl_atomic_inc( p_val );\r
913                 __lock_po_code( p_ext );\r
914         }\r
915         else\r
916         {\r
917                 __unlock_po_code( p_ext );\r
918                 cl_atomic_dec( p_val );\r
919         }\r
920 \r
921         /* \r
922          * Set the flag in the device extension to indicate that power management\r
923          * can happen at elevated IRQL.\r
924          */\r
925         if( p_ext->n_paging_files || \r
926                 p_ext->n_crash_files || \r
927                 p_ext->n_hibernate_files )\r
928         {\r
929                 p_dev_obj->Flags &= ~DO_POWER_PAGABLE;\r
930         }\r
931         else\r
932         {\r
933                 p_dev_obj->Flags |= DO_POWER_PAGABLE;\r
934         }\r
935 \r
936         /* Call type specific (FDO, PDO) function for propagating the IRP. */\r
937         status = p_ext->vfptr_pnp_po->pfn_dev_usage_notification( \r
938                 p_dev_obj, p_irp, p_action );\r
939 \r
940         if( NT_SUCCESS( status ) )\r
941         {\r
942                 /* Notify the PnP manager that the device state may have changed. */\r
943                 IoInvalidateDeviceState( p_ext->p_pdo );\r
944         }\r
945         else\r
946         {\r
947                 /* Propagation failed.  Undo. */\r
948                 if( p_io_stack->Parameters.UsageNotification.InPath )\r
949                 {\r
950                         /* Someone does not support the type of special file requested. */\r
951                         __unlock_po_code( p_ext );\r
952                         cl_atomic_dec( p_val );\r
953                 }\r
954                 else\r
955                 {\r
956                         /* \r
957                          * Someone failed the notification for the removal of a special\r
958                          * file.  This is unlikely to happen, but handle it anyway.\r
959                          */\r
960                         cl_atomic_inc( p_val );\r
961                         __lock_po_code( p_ext );\r
962                 }\r
963 \r
964                 /* \r
965                  * Set the flag in the device extension to indicate that power \r
966                  * management can happen at elevated IRQL.\r
967                  */\r
968                 if( p_ext->n_paging_files || \r
969                         p_ext->n_crash_files || \r
970                         p_ext->n_hibernate_files )\r
971                 {\r
972                         p_dev_obj->Flags &= ~DO_POWER_PAGABLE;\r
973                 }\r
974                 else\r
975                 {\r
976                         p_dev_obj->Flags |= DO_POWER_PAGABLE;\r
977                 }\r
978         }\r
979 \r
980         CL_EXIT( CL_DBG_PNP, p_ext->dbg_lvl );\r
981         return status;\r
982 }\r
983 \r
984 \r
985 static NTSTATUS\r
986 __query_device_relations(\r
987         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
988         IN                              IRP* const                                      p_irp, \r
989                 OUT                     cl_irp_action_t* const          p_action )\r
990 {\r
991         NTSTATUS                        status;\r
992         IO_STACK_LOCATION       *p_io_stack;\r
993         cl_pnp_po_ext_t         *p_ext;\r
994 \r
995         p_ext = p_dev_obj->DeviceExtension;\r
996 \r
997         CL_ENTER( CL_DBG_PNP, p_ext->dbg_lvl );\r
998 \r
999         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
1000 \r
1001         switch( p_io_stack->Parameters.QueryDeviceRelations.Type )\r
1002         {\r
1003         case BusRelations:\r
1004                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("BusRelations for %s\n", \r
1005                         p_ext->vfptr_pnp_po->identity) );\r
1006                 status = p_ext->vfptr_pnp_po->pfn_query_bus_relations( \r
1007                         p_dev_obj, p_irp, p_action );\r
1008                 break;\r
1009 \r
1010         case EjectionRelations:\r
1011                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("EjectionRelations for %s\n",\r
1012                         p_ext->vfptr_pnp_po->identity) );\r
1013                 status = p_ext->vfptr_pnp_po->pfn_query_ejection_relations(\r
1014                         p_dev_obj, p_irp, p_action );\r
1015                 break;\r
1016 \r
1017         case RemovalRelations:\r
1018                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("RemovalRelations for %s\n",\r
1019                         p_ext->vfptr_pnp_po->identity) );\r
1020                 status = p_ext->vfptr_pnp_po->pfn_query_removal_relations(\r
1021                         p_dev_obj, p_irp, p_action );\r
1022                 break;\r
1023 \r
1024         case TargetDeviceRelation:\r
1025                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("TargetDeviceRelation for %s\n", \r
1026                         p_ext->vfptr_pnp_po->identity) );\r
1027                 status = p_ext->vfptr_pnp_po->pfn_query_target_relations(\r
1028                         p_dev_obj, p_irp, p_action );\r
1029                 break;\r
1030 \r
1031         default:\r
1032                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("Unknown Relation for %s\n", \r
1033                         p_ext->vfptr_pnp_po->identity) );\r
1034                 status = p_ext->vfptr_pnp_po->pfn_unknown(\r
1035                         p_dev_obj, p_irp, p_action );\r
1036                 break;\r
1037         }\r
1038 \r
1039         CL_EXIT( CL_DBG_PNP, p_ext->dbg_lvl );\r
1040         return status;\r
1041 }\r
1042 \r
1043 \r
1044 static NTSTATUS\r
1045 __query_id(\r
1046         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1047         IN                                      IRP* const                              p_irp, \r
1048                 OUT                             cl_irp_action_t* const  p_action )\r
1049 {\r
1050         NTSTATUS                        status;\r
1051         IO_STACK_LOCATION       *p_io_stack;\r
1052         cl_pnp_po_ext_t         *p_ext;\r
1053 \r
1054         p_ext = p_dev_obj->DeviceExtension;\r
1055 \r
1056         CL_ENTER( CL_DBG_PNP, p_ext->dbg_lvl );\r
1057         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
1058 \r
1059         /* Only PDOs handle query ID and query text IRPs */\r
1060         if( p_ext->p_next_do )\r
1061         {\r
1062                 status = cl_irp_ignore( p_dev_obj, p_irp, p_action );\r
1063                 CL_EXIT( CL_DBG_PNP, p_ext->dbg_lvl );\r
1064                 return status;\r
1065         }\r
1066 \r
1067         *p_action = IrpComplete;\r
1068 \r
1069         switch( p_io_stack->Parameters.QueryId.IdType )\r
1070         {\r
1071         case BusQueryDeviceID:\r
1072                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("BusQueryDeviceID for %s\n",\r
1073                         p_ext->vfptr_pnp_po->identity) );\r
1074                 status = \r
1075                         p_ext->vfptr_query_txt->pfn_query_device_id( p_dev_obj, p_irp );\r
1076                 break;\r
1077 \r
1078         case BusQueryHardwareIDs:\r
1079                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("BusQueryHardwareIDs for %s\n",\r
1080                         p_ext->vfptr_pnp_po->identity) );\r
1081                 status = \r
1082                         p_ext->vfptr_query_txt->pfn_query_hardware_id( p_dev_obj, p_irp );\r
1083                 break;\r
1084 \r
1085         case BusQueryCompatibleIDs:\r
1086                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("BusQueryCompatibleIDs for %s\n",\r
1087                         p_ext->vfptr_pnp_po->identity) );\r
1088                 status = p_ext->vfptr_query_txt->pfn_query_compatible_id( \r
1089                         p_dev_obj, p_irp );\r
1090                 break;\r
1091 \r
1092         case BusQueryInstanceID:\r
1093                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("BusQueryInstanceID for %s\n",\r
1094                         p_ext->vfptr_pnp_po->identity) );\r
1095                 status = \r
1096                         p_ext->vfptr_query_txt->pfn_query_unique_id( p_dev_obj, p_irp );\r
1097                 break;\r
1098 \r
1099         default:\r
1100                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("Unsupported ID type for %s\n",\r
1101                         p_ext->vfptr_pnp_po->identity) );\r
1102                 status = p_irp->IoStatus.Status;\r
1103                 break;\r
1104         }\r
1105 \r
1106         CL_EXIT( CL_DBG_PNP, p_ext->dbg_lvl );\r
1107         return status;\r
1108 }\r
1109 \r
1110 \r
1111 static NTSTATUS\r
1112 __query_device_text(\r
1113         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1114         IN                              IRP* const                                      p_irp, \r
1115                 OUT                     cl_irp_action_t* const          p_action )\r
1116 {\r
1117         NTSTATUS                        status;\r
1118         cl_pnp_po_ext_t         *p_ext;\r
1119         IO_STACK_LOCATION       *p_io_stack;\r
1120 \r
1121         p_ext = p_dev_obj->DeviceExtension;\r
1122 \r
1123         CL_ENTER( CL_DBG_PNP, p_ext->dbg_lvl );\r
1124 \r
1125         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
1126 \r
1127         /* Only PDOs handle query ID and query text IRPs */\r
1128         if( p_ext->p_next_do )\r
1129         {\r
1130                 status = cl_irp_ignore( p_dev_obj, p_irp, p_action );\r
1131                 CL_EXIT( CL_DBG_PNP, p_ext->dbg_lvl );\r
1132                 return status;\r
1133         }\r
1134 \r
1135         *p_action = IrpComplete;\r
1136 \r
1137         switch( p_io_stack->Parameters.QueryDeviceText.DeviceTextType )\r
1138         {\r
1139         case DeviceTextDescription:\r
1140                 status = \r
1141                         p_ext->vfptr_query_txt->pfn_query_description( p_dev_obj, p_irp );\r
1142                 break;\r
1143 \r
1144         case DeviceTextLocationInformation:\r
1145                 status = \r
1146                         p_ext->vfptr_query_txt->pfn_query_location( p_dev_obj, p_irp );\r
1147                 break;\r
1148 \r
1149         default:\r
1150                 status = p_irp->IoStatus.Status;\r
1151                 break;\r
1152         }\r
1153 \r
1154         CL_EXIT( CL_DBG_PNP, p_ext->dbg_lvl );\r
1155         return status;\r
1156 }\r
1157 \r
1158 \r
1159 static NTSTATUS\r
1160 __sync_completion(\r
1161         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
1162         IN                              IRP                                                     *p_irp,\r
1163         IN                              void                                            *context )\r
1164 {\r
1165         UNUSED_PARAM( p_dev_obj );\r
1166 \r
1167         ASSERT( p_irp );\r
1168         ASSERT( context );\r
1169 \r
1170         /* \r
1171          * We only wait if IoCallDriver returned STATUS_PENDING.  Only set\r
1172          * the event if the IRP returned pending, so that we don't needlessly\r
1173          * signal it.\r
1174          */\r
1175         if( p_irp->PendingReturned )\r
1176                 KeSetEvent( (KEVENT*)context, IO_NO_INCREMENT, FALSE );\r
1177 \r
1178         /* We need to process the IRP further. */\r
1179         return STATUS_MORE_PROCESSING_REQUIRED;\r
1180 }\r
1181 \r
1182 \r
1183 NTSTATUS\r
1184 cl_do_sync_pnp(\r
1185         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1186         IN                              IRP* const                                      p_irp,\r
1187                 OUT                     cl_irp_action_t* const          p_action )\r
1188 {\r
1189         KEVENT                          event;\r
1190         NTSTATUS                        status;\r
1191         cl_pnp_po_ext_t *p_ext;\r
1192 \r
1193         p_ext = p_dev_obj->DeviceExtension;\r
1194 \r
1195         CL_ENTER( CL_DBG_PNP, p_ext->dbg_lvl );\r
1196 \r
1197         KeInitializeEvent( &event, NotificationEvent, FALSE );\r
1198 \r
1199         /* Setup the IRP. */\r
1200         IoCopyCurrentIrpStackLocationToNext( p_irp );\r
1201 #pragma warning( push, 3 )\r
1202         IoSetCompletionRoutine( p_irp, __sync_completion, &event, \r
1203                 TRUE, TRUE, TRUE );\r
1204 #pragma warning( pop )\r
1205 \r
1206         status = IoCallDriver( p_ext->p_next_do, p_irp );\r
1207         if( status == STATUS_PENDING )\r
1208         {\r
1209                 /* Wait for the completion. */\r
1210                 KeWaitForSingleObject( &event, Executive, KernelMode, \r
1211                         FALSE, NULL );\r
1212 \r
1213                 status = p_irp->IoStatus.Status;\r
1214         }\r
1215         *p_action = IrpComplete;\r
1216         CL_EXIT( CL_DBG_PNP, p_ext->dbg_lvl );\r
1217         return status;\r
1218 }\r
1219 \r
1220 \r
1221 NTSTATUS\r
1222 cl_alloc_relations(\r
1223         IN                              IRP* const                                      p_irp,\r
1224         IN              const   size_t                                          n_devs )\r
1225 {\r
1226         DEVICE_RELATIONS        *p_rel, *p_old_rel;\r
1227         size_t                          alloc_size;\r
1228 #ifdef _DEBUG_\r
1229         /* Debug variable to prevent warnings when using CL_TRACE macros. */\r
1230         uint32_t                        dbg_error = CL_DBG_ERROR;\r
1231 #endif\r
1232 \r
1233         ASSERT( n_devs );\r
1234 \r
1235         alloc_size = sizeof(DEVICE_RELATIONS) + \r
1236                 (sizeof(PDEVICE_OBJECT) * (n_devs - 1));\r
1237         \r
1238         /* If there are already relations, copy them. */\r
1239         p_old_rel = (DEVICE_RELATIONS*)p_irp->IoStatus.Information;\r
1240         if( p_old_rel )\r
1241                 alloc_size += (sizeof(PDEVICE_OBJECT) * p_old_rel->Count);\r
1242 \r
1243         /* Allocate the new relations structure. */\r
1244         p_rel = ExAllocatePoolWithTag( PagedPool, alloc_size, 'ralc' );\r
1245         p_irp->IoStatus.Information = (ULONG_PTR)p_rel;\r
1246         if( !p_rel )\r
1247         {\r
1248                 /* \r
1249                  * Allocation failed.  Release the existing relations and fail the IRP.\r
1250                  */\r
1251                 if( p_old_rel )\r
1252                         ExFreePool( p_old_rel );\r
1253                 CL_TRACE( CL_DBG_ERROR, dbg_error, \r
1254                         ("Failed to allocate DEVICE_RELATIONS (%d bytes).\n", alloc_size) );\r
1255                 return STATUS_INSUFFICIENT_RESOURCES;\r
1256         }\r
1257 \r
1258         /* \r
1259          * Since the structure doesn't contain the callers target devices,\r
1260          * the count is only set to what existing relations specify.\r
1261          */\r
1262         if( p_old_rel )\r
1263         {\r
1264                 /* Copy the existing relations. */\r
1265                 RtlCopyMemory( p_rel->Objects, p_old_rel->Objects, \r
1266                         sizeof(PDEVICE_OBJECT) * p_old_rel->Count );\r
1267                 p_rel->Count = p_old_rel->Count;\r
1268                 /* Done with the copy, free the old relations structure. */\r
1269                 ExFreePool( p_old_rel );\r
1270         }\r
1271         else\r
1272         {\r
1273                 p_rel->Count = 0;\r
1274         }\r
1275 \r
1276         return STATUS_SUCCESS;\r
1277 }\r
1278 \r
1279 \r
1280 NTSTATUS\r
1281 cl_power(\r
1282         IN                              PDEVICE_OBJECT                          p_dev_obj,\r
1283         IN                              PIRP                                            p_irp )\r
1284 {\r
1285         NTSTATUS                        status;\r
1286         IO_STACK_LOCATION       *p_io_stack;\r
1287         cl_pnp_po_ext_t         *p_ext;\r
1288         cl_irp_action_t         action;\r
1289 \r
1290         p_ext = p_dev_obj->DeviceExtension;\r
1291 \r
1292         CL_ENTER( CL_DBG_PNP, p_ext->dbg_lvl );\r
1293 \r
1294         status = IoAcquireRemoveLock( &p_ext->remove_lock, p_irp );\r
1295         if( !NT_SUCCESS( status ) )\r
1296         {\r
1297                 CL_TRACE_EXIT( CL_DBG_ERROR, p_ext->dbg_lvl, \r
1298                         ("IoAcquireRemoveLock returned %08x for %s.\n",\r
1299                         status, p_ext->vfptr_pnp_po->identity) );\r
1300                 PoStartNextPowerIrp( p_irp );\r
1301                 p_irp->IoStatus.Status = status;\r
1302                 IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
1303                 return status;\r
1304         }\r
1305 \r
1306         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
1307         ASSERT( p_io_stack->MajorFunction == IRP_MJ_POWER );\r
1308 \r
1309         switch( p_io_stack->MinorFunction )\r
1310         {\r
1311         case IRP_MN_QUERY_POWER:\r
1312                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("IRP_MN_QUERY_POWER for %s\n", \r
1313                         p_ext->vfptr_pnp_po->identity) );\r
1314                 status = \r
1315                         p_ext->vfptr_pnp_po->pfn_query_power( p_dev_obj, p_irp, &action );\r
1316                 break;\r
1317 \r
1318         case IRP_MN_SET_POWER:\r
1319                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("IRP_MN_SET_POWER for %s\n", \r
1320                         p_ext->vfptr_pnp_po->identity) );\r
1321                 status = \r
1322                         p_ext->vfptr_pnp_po->pfn_set_power( p_dev_obj, p_irp, &action );\r
1323                 break;\r
1324 \r
1325         case IRP_MN_WAIT_WAKE:\r
1326                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("IRP_MN_WAIT_WAKE for %s\n", \r
1327                         p_ext->vfptr_pnp_po->identity) );\r
1328                 status = \r
1329                         p_ext->vfptr_pnp_po->pfn_wait_wake( p_dev_obj, p_irp, &action );\r
1330                 break;\r
1331 \r
1332         case IRP_MN_POWER_SEQUENCE:\r
1333                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("IRP_MN_POWER_SEQUENCE for %s\n", \r
1334                         p_ext->vfptr_pnp_po->identity) );\r
1335                 status = \r
1336                         p_ext->vfptr_pnp_po->pfn_power_sequence( p_dev_obj, p_irp, &action );\r
1337                 break;\r
1338                 \r
1339         default:\r
1340                 CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("Unknown IRP minor function for %s\n", \r
1341                         p_ext->vfptr_pnp_po->identity) );\r
1342                 status = p_ext->vfptr_pnp_po->pfn_unknown(\r
1343                         p_dev_obj, p_irp, &action );\r
1344         }\r
1345 \r
1346         switch( action )\r
1347         {\r
1348         case IrpPassDown:\r
1349                 /* \r
1350                  * A completion routine has already been set.\r
1351                  * PoStartNextPowerIrp should be called in the completion routine.\r
1352                  */\r
1353                 status = PoCallDriver( p_ext->p_next_do, p_irp );\r
1354                 break;\r
1355 \r
1356         case IrpSkip:\r
1357                 p_irp->IoStatus.Status = status;\r
1358 \r
1359         case IrpIgnore:\r
1360                 PoStartNextPowerIrp( p_irp );\r
1361                 IoSkipCurrentIrpStackLocation( p_irp );\r
1362                 /* TODO: Documentation says to return STATUS_PENDING.  Seems odd. */\r
1363                 status = PoCallDriver( p_ext->p_next_do, p_irp );\r
1364                 break;\r
1365 \r
1366         case IrpComplete:\r
1367                 p_irp->IoStatus.Status = status;\r
1368                 PoStartNextPowerIrp( p_irp );\r
1369                 IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
1370                 break;\r
1371 \r
1372         case IrpDoNothing:\r
1373                 /* \r
1374                  * Returned when sending a device IRP_MN_SET_POWER IRP so that\r
1375                  * processing can continue in the completion routine without releasing\r
1376                  * the remove lock.\r
1377                  */\r
1378                 break;\r
1379         }\r
1380 \r
1381         if( action != IrpDoNothing )\r
1382                 IoReleaseRemoveLock( &p_ext->remove_lock, p_irp );\r
1383 \r
1384         CL_EXIT( CL_DBG_PNP, p_ext->dbg_lvl );\r
1385         return status;\r
1386 }\r
1387 \r
1388 \r
1389 NTSTATUS\r
1390 cl_irp_skip(\r
1391         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1392         IN                              IRP* const                                      p_irp, \r
1393                 OUT                     cl_irp_action_t* const          p_action )\r
1394 {\r
1395         UNUSED_PARAM( p_dev_obj );\r
1396         UNUSED_PARAM( p_irp );\r
1397         *p_action = IrpSkip;\r
1398         return STATUS_SUCCESS;\r
1399 }\r
1400 \r
1401 \r
1402 NTSTATUS\r
1403 cl_irp_ignore(\r
1404         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1405         IN                              IRP* const                                      p_irp, \r
1406                 OUT                     cl_irp_action_t* const          p_action )\r
1407 {\r
1408         UNUSED_PARAM( p_dev_obj );\r
1409         UNUSED_PARAM( p_irp );\r
1410         *p_action = IrpIgnore;\r
1411         return STATUS_SUCCESS;\r
1412 }\r
1413 \r
1414 \r
1415 \r
1416 NTSTATUS\r
1417 cl_irp_complete(\r
1418         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1419         IN                              IRP* const                                      p_irp, \r
1420                 OUT                     cl_irp_action_t* const          p_action )\r
1421 {\r
1422         UNUSED_PARAM( p_dev_obj );\r
1423         *p_action = IrpComplete;\r
1424         return p_irp->IoStatus.Status;\r
1425 }\r
1426 \r
1427 \r
1428 NTSTATUS\r
1429 cl_irp_succeed(\r
1430         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1431         IN                              IRP* const                                      p_irp, \r
1432                 OUT                     cl_irp_action_t* const          p_action )\r
1433 {\r
1434         UNUSED_PARAM( p_dev_obj );\r
1435         UNUSED_PARAM( p_irp );\r
1436         *p_action = IrpComplete;\r
1437         return STATUS_SUCCESS;\r
1438 }\r
1439 \r
1440 \r
1441 NTSTATUS\r
1442 cl_irp_unsupported(\r
1443         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1444         IN                              IRP* const                                      p_irp, \r
1445                 OUT                     cl_irp_action_t* const          p_action )\r
1446 {\r
1447         UNUSED_PARAM( p_dev_obj );\r
1448         UNUSED_PARAM( p_irp );\r
1449         *p_action = IrpComplete;\r
1450         return STATUS_NOT_SUPPORTED;\r
1451 }\r