617ffd820114e533705091a11c517859855a63da
[mirror/winof/.git] / core / iou / kernel / iou_pnp.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 \r
34 /*\r
35  * Implemenation of all PnP functionality for FDO (power policy owners).\r
36  */\r
37 \r
38 \r
39 #include "iou_driver.h"\r
40 #if defined(EVENT_TRACING)\r
41 #ifdef offsetof\r
42 #undef offsetof\r
43 #endif\r
44 #include "iou_pnp.tmh"\r
45 #endif\r
46 #include "iou_pnp.h"\r
47 #include "iou_ioc_mgr.h"\r
48 #include <complib/cl_memory.h>\r
49 #include <complib/cl_bus_ifc.h>\r
50 #include <initguid.h>\r
51 #include <iba/iou_ifc.h>\r
52 \r
53 \r
54 static NTSTATUS\r
55 fdo_start(\r
56         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
57         IN                                      IRP* const                              p_irp, \r
58                 OUT                             cl_irp_action_t* const  p_action );\r
59 \r
60 static void\r
61 fdo_release_resources(\r
62         IN                                      DEVICE_OBJECT* const    p_dev_obj );\r
63 \r
64 static NTSTATUS\r
65 fdo_query_remove(\r
66         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
67         IN                                      IRP* const                              p_irp, \r
68                 OUT                             cl_irp_action_t* const  p_action );\r
69 \r
70 static NTSTATUS\r
71 fdo_query_capabilities(\r
72         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
73         IN                                      IRP* const                              p_irp, \r
74                 OUT                             cl_irp_action_t* const  p_action );\r
75 \r
76 static NTSTATUS\r
77 fdo_query_iou_relations(\r
78         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
79         IN                                      IRP* const                              p_irp, \r
80                 OUT                             cl_irp_action_t* const  p_action );\r
81 \r
82 static NTSTATUS\r
83 fdo_query_interface(\r
84         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
85         IN                              IRP* const                                      p_irp, \r
86                 OUT                     cl_irp_action_t* const          p_action );\r
87 \r
88 static NTSTATUS\r
89 __fdo_query_power(\r
90         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
91         IN                              IRP* const                                      p_irp,\r
92                 OUT                     cl_irp_action_t* const          p_action );\r
93 \r
94 static NTSTATUS\r
95 __fdo_set_power(\r
96         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
97         IN                              IRP* const                                      p_irp,\r
98                 OUT                     cl_irp_action_t* const          p_action );\r
99 \r
100 \r
101 \r
102 /* Global virtual function pointer tables shared between all instances of FDO. */\r
103 static const cl_vfptr_pnp_po_t          vfptr_fdo_pnp = {\r
104         "IB IOU",\r
105         fdo_start,\r
106         cl_irp_skip,\r
107         cl_irp_skip,\r
108         cl_do_sync_pnp,\r
109         fdo_query_remove,\r
110         fdo_release_resources,\r
111         cl_do_remove,\r
112         cl_do_sync_pnp,\r
113         cl_irp_skip,\r
114         fdo_query_capabilities,\r
115         cl_irp_skip,\r
116         cl_irp_skip,\r
117         cl_do_sync_pnp,\r
118         fdo_query_iou_relations,\r
119         cl_irp_ignore,\r
120         cl_irp_ignore,\r
121         cl_irp_ignore,\r
122         cl_irp_ignore,\r
123         cl_irp_ignore,\r
124         cl_irp_ignore,\r
125         cl_irp_ignore,\r
126         cl_irp_ignore,                  /* QueryInterface */\r
127         cl_irp_ignore,\r
128         cl_irp_ignore,\r
129         cl_irp_ignore,\r
130         cl_irp_ignore,\r
131         __fdo_query_power,              /* QueryPower */\r
132         __fdo_set_power,                /* SetPower */\r
133         cl_irp_ignore,                  /* PowerSequence */\r
134         cl_irp_ignore                   /* WaitWake */\r
135 };\r
136 /*\r
137  * NOTE: The QueryInterface entry point is not used because we only enable/disable\r
138  * our interface so that user-mode AL can find a device to perform IOCTLs to.\r
139  */\r
140 \r
141 \r
142 NTSTATUS\r
143 iou_add_device(\r
144         IN                              DRIVER_OBJECT                           *p_driver_obj,\r
145         IN                              DEVICE_OBJECT                           *p_pdo )\r
146 {\r
147         NTSTATUS                status;\r
148         DEVICE_OBJECT   *p_dev_obj, *p_next_do;\r
149         iou_fdo_ext_t   *p_ext;\r
150 \r
151         IOU_ENTER( IOU_DBG_PNP );\r
152 \r
153         /* Create the FDO device object to attach to the stack. */\r
154         status = IoCreateDevice( p_driver_obj, sizeof(iou_fdo_ext_t),\r
155                 NULL, FILE_DEVICE_BUS_EXTENDER,\r
156                 FILE_DEVICE_SECURE_OPEN, FALSE, &p_dev_obj );\r
157         if( !NT_SUCCESS(status) )\r
158         {\r
159                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
160                         ("Failed to create bus root FDO device.\n") );\r
161                 return status;\r
162         }\r
163 \r
164         p_ext = p_dev_obj->DeviceExtension;\r
165 \r
166         ioc_mgr_construct( &p_ext->ioc_mgr );\r
167 \r
168         p_next_do = IoAttachDeviceToDeviceStack( p_dev_obj, p_pdo );\r
169         if( !p_next_do )\r
170         {\r
171                 IoDeleteDevice( p_dev_obj );\r
172                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
173                         ("IoAttachToDeviceStack failed.\n") );\r
174                 return STATUS_NO_SUCH_DEVICE;\r
175         }\r
176 \r
177         cl_init_pnp_po_ext( p_dev_obj, p_next_do, p_pdo, g_iou_dbg_flags,\r
178                 &vfptr_fdo_pnp, NULL );\r
179 \r
180         IOU_EXIT( IOU_DBG_PNP );\r
181         return STATUS_SUCCESS;\r
182 }\r
183 \r
184 \r
185 static NTSTATUS\r
186 __get_iou_ifc(\r
187         IN                                      iou_fdo_ext_t* const    p_ext )\r
188 {\r
189         NTSTATUS                        status;\r
190         IO_STACK_LOCATION       io_stack;\r
191         ib_al_ifc_data_t        data;\r
192 \r
193         IOU_ENTER( IOU_DBG_PNP );\r
194 \r
195         data.type = &GUID_IOU_INTERFACE_DATA;\r
196         data.version = IOU_INTERFACE_DATA_VERSION;\r
197         data.size = sizeof(iou_ifc_data_t);\r
198         data.p_data = &p_ext->ioc_mgr.info;\r
199 \r
200         io_stack.MinorFunction = IRP_MN_QUERY_INTERFACE;\r
201         io_stack.Parameters.QueryInterface.Version = AL_INTERFACE_VERSION;\r
202         io_stack.Parameters.QueryInterface.Size = sizeof(ib_al_ifc_t);\r
203         io_stack.Parameters.QueryInterface.Interface =\r
204                 (INTERFACE*)&p_ext->ioc_mgr.ifc;\r
205         io_stack.Parameters.QueryInterface.InterfaceSpecificData =\r
206                 &data;\r
207         io_stack.Parameters.QueryInterface.InterfaceType = &GUID_IB_AL_INTERFACE;\r
208 \r
209         status = cl_fwd_query_ifc( p_ext->cl_ext.p_next_do, &io_stack );\r
210 \r
211         /*\r
212          * Dereference the interface now so that the bus driver doesn't fail a\r
213          * query remove IRP.  We will always get unloaded before the bus driver\r
214          * since we're a child device.\r
215          */\r
216         if( NT_SUCCESS( status ) )\r
217         {\r
218                 p_ext->ioc_mgr.ifc.wdm.InterfaceDereference(\r
219                         p_ext->ioc_mgr.ifc.wdm.Context );\r
220         }\r
221 \r
222         IOU_EXIT( IOU_DBG_PNP );\r
223         return status;\r
224 }\r
225 \r
226 \r
227 static NTSTATUS\r
228 fdo_start(\r
229         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
230         IN                                      IRP* const                              p_irp, \r
231                 OUT                             cl_irp_action_t* const  p_action )\r
232 {\r
233         NTSTATUS                status;\r
234         iou_fdo_ext_t   *p_ext;\r
235         ib_api_status_t ib_status;\r
236 \r
237         IOU_ENTER( IOU_DBG_PNP );\r
238 \r
239         p_ext = p_dev_obj->DeviceExtension;\r
240 \r
241         /* Handled on the way up. */\r
242         status = cl_do_sync_pnp( p_dev_obj, p_irp, p_action );\r
243         if( !NT_SUCCESS( status ) )\r
244         {\r
245                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
246                         ("Lower drivers failed IRP_MN_START_DEVICE.\n") );\r
247                 return status;\r
248         }\r
249 \r
250         status = __get_iou_ifc( p_ext );\r
251         if( !NT_SUCCESS( status ) )\r
252         {\r
253                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
254                         ("Failed to get IOU interface.\n") );\r
255                 return status;\r
256         }\r
257 \r
258         /* Initialize the IOU manager. */\r
259         ib_status = ioc_mgr_init( &p_ext->ioc_mgr );\r
260         if( ib_status != IB_SUCCESS )\r
261         {\r
262                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
263                         ("ioc_mgr_init returned %s.\n",\r
264                         p_ext->ioc_mgr.ifc.get_err_str(ib_status)) );\r
265                 return STATUS_UNSUCCESSFUL;\r
266         }\r
267 \r
268         IOU_EXIT( IOU_DBG_PNP );\r
269         return status;\r
270 }\r
271 \r
272 \r
273 static NTSTATUS\r
274 fdo_query_remove(\r
275         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
276         IN                                      IRP* const                              p_irp, \r
277                 OUT                             cl_irp_action_t* const  p_action )\r
278 {\r
279         iou_fdo_ext_t   *p_ext;\r
280 \r
281         IOU_ENTER( IOU_DBG_PNP );\r
282 \r
283         p_ext = p_dev_obj->DeviceExtension;\r
284 \r
285         *p_action = IrpSkip;\r
286         /* The FDO driver must set the status even when passing down. */\r
287         p_irp->IoStatus.Status = STATUS_SUCCESS;\r
288         IOU_EXIT( IOU_DBG_PNP );\r
289         return STATUS_SUCCESS;\r
290 }\r
291 \r
292 \r
293 /*\r
294  * This function gets called after releasing the remove lock and waiting\r
295  * for all other threads to release the lock.  No more modifications will\r
296  * occur to the PDO pointer vectors.\r
297  */\r
298 static void\r
299 fdo_release_resources(\r
300         IN                                      DEVICE_OBJECT* const    p_dev_obj )\r
301 {\r
302         iou_fdo_ext_t   *p_ext;\r
303 \r
304         IOU_ENTER( IOU_DBG_PNP );\r
305 \r
306         p_ext = p_dev_obj->DeviceExtension;\r
307 \r
308         //TODO: Fail outstanding I/O operations.\r
309         cl_obj_destroy( &p_ext->ioc_mgr.obj );\r
310 \r
311         IOU_EXIT( IOU_DBG_PNP );\r
312 }\r
313 \r
314 \r
315 static NTSTATUS\r
316 fdo_query_capabilities(\r
317         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
318         IN                                      IRP* const                              p_irp, \r
319                 OUT                             cl_irp_action_t* const  p_action )\r
320 {\r
321         NTSTATUS                        status;\r
322         iou_fdo_ext_t           *p_ext;\r
323         IO_STACK_LOCATION       *p_io_stack;\r
324 \r
325         IOU_ENTER( IOU_DBG_PNP );\r
326 \r
327         p_ext = p_dev_obj->DeviceExtension;\r
328 \r
329         /* Process on the way up. */\r
330         status = cl_do_sync_pnp( p_dev_obj, p_irp, p_action );\r
331 \r
332         if( !NT_SUCCESS( status ) )\r
333         {\r
334                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
335                         ("cl_do_sync_pnp returned %08x.\n", status) );\r
336                 return status;\r
337         }\r
338 \r
339         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
340 \r
341         /*\r
342          * Store the device power maping into our extension since we're\r
343          * the power policy owner.  The mapping is used when handling\r
344          * IRP_MN_SET_POWER IRPs.\r
345          */\r
346         cl_memcpy( p_ext->po_state, \r
347                 p_io_stack->Parameters.DeviceCapabilities.Capabilities->DeviceState,\r
348                 sizeof( p_ext->po_state ) );\r
349 \r
350         IOU_EXIT( IOU_DBG_PNP );\r
351         return status;\r
352 }\r
353 \r
354 \r
355 static NTSTATUS\r
356 fdo_query_iou_relations(\r
357         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
358         IN                              IRP* const                                      p_irp, \r
359                 OUT                     cl_irp_action_t* const          p_action )\r
360 {\r
361         iou_fdo_ext_t   *p_ext;\r
362         NTSTATUS                status;\r
363 \r
364         IOU_ENTER( IOU_DBG_PNP );\r
365 \r
366         p_ext = p_dev_obj->DeviceExtension;\r
367 \r
368         status = ioc_mgr_get_iou_relations( &p_ext->ioc_mgr, p_irp );\r
369         switch( status )\r
370         {\r
371         case STATUS_NO_SUCH_DEVICE:\r
372                 *p_action = IrpSkip;\r
373                 status = STATUS_SUCCESS;\r
374                 break;\r
375 \r
376         case STATUS_SUCCESS:\r
377                 *p_action = IrpPassDown;\r
378                 break;\r
379 \r
380         default:\r
381                 *p_action = IrpComplete;\r
382                 break;\r
383         }\r
384 \r
385         IOU_EXIT( IOU_DBG_PNP );\r
386         return status;\r
387 }\r
388 \r
389 \r
390 static NTSTATUS\r
391 __fdo_query_power(\r
392         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
393         IN                              IRP* const                                      p_irp,\r
394                 OUT                     cl_irp_action_t* const          p_action )\r
395 {\r
396         NTSTATUS                        status = STATUS_SUCCESS;\r
397         IO_STACK_LOCATION       *p_io_stack;\r
398 \r
399         IOU_ENTER( IOU_DBG_POWER );\r
400 \r
401         UNUSED_PARAM( p_dev_obj );\r
402 \r
403         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
404 \r
405         switch( p_io_stack->Parameters.Power.Type )\r
406         {\r
407         case SystemPowerState:\r
408                 /* Fail any requests to hibernate or sleep the system. */\r
409                 switch( p_io_stack->Parameters.Power.State.SystemState )\r
410                 {\r
411                         case PowerSystemWorking:\r
412                         case PowerSystemShutdown:\r
413                                 /* We only support fully working and shutdown system states. */\r
414                                 break;\r
415 \r
416                         default:\r
417                                 status = STATUS_NOT_SUPPORTED;\r
418                 }\r
419                 break;\r
420 \r
421         case DevicePowerState:\r
422                 /* Fail any query for low power states. */\r
423                 switch( p_io_stack->Parameters.Power.State.DeviceState )\r
424                 {\r
425                 case PowerDeviceD0:\r
426                 case PowerDeviceD3:\r
427                         /* We only support fully powered or off power states. */\r
428                         break;\r
429 \r
430                 default:\r
431                         status = STATUS_NOT_SUPPORTED;\r
432                 }\r
433                 break;\r
434         }\r
435 \r
436         if( status == STATUS_NOT_SUPPORTED )\r
437                 *p_action = IrpComplete;\r
438         else\r
439                 *p_action = IrpSkip;\r
440 \r
441         IOU_EXIT( IOU_DBG_POWER );\r
442         return status;\r
443 }\r
444 \r
445 \r
446 static void\r
447 __request_power_completion(\r
448         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
449         IN                              UCHAR                                           minor_function,\r
450         IN                              POWER_STATE                                     power_state,\r
451         IN                              void                                            *context,\r
452         IN                              IO_STATUS_BLOCK                         *p_io_status )\r
453 {\r
454         IRP                                     *p_irp;\r
455         cl_pnp_po_ext_t         *p_ext;\r
456 \r
457         IOU_ENTER( IOU_DBG_PNP );\r
458 \r
459         UNUSED_PARAM( minor_function );\r
460         UNUSED_PARAM( power_state );\r
461 \r
462         p_irp = (IRP*)context;\r
463         p_ext = p_dev_obj->DeviceExtension;\r
464 \r
465         /* Propagate the device IRP status to the system IRP status. */\r
466         p_irp->IoStatus.Status = p_io_status->Status;\r
467 \r
468         /* Continue Power IRP processing. */\r
469         PoStartNextPowerIrp( p_irp );\r
470         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
471         IoReleaseRemoveLock( &p_ext->remove_lock, p_irp );\r
472         IOU_EXIT( IOU_DBG_PNP );\r
473 }\r
474 \r
475 \r
476 /*NOTE: Completion routines must NEVER be pageable. */\r
477 static NTSTATUS\r
478 __set_power_completion(\r
479         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
480         IN                              IRP                                                     *p_irp,\r
481         IN                              void                                            *context )\r
482 {\r
483         NTSTATUS                        status;\r
484         POWER_STATE                     state;\r
485         iou_fdo_ext_t           *p_ext;\r
486         IO_STACK_LOCATION       *p_io_stack;\r
487 \r
488         IOU_ENTER( IOU_DBG_PNP );\r
489 \r
490         UNUSED_PARAM( context );\r
491 \r
492         p_ext = p_dev_obj->DeviceExtension;\r
493         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
494 \r
495         if( !NT_SUCCESS( p_irp->IoStatus.Status ) )\r
496         {\r
497                 PoStartNextPowerIrp( p_irp );\r
498                 IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
499                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
500                         ("IRP_MN_SET_POWER for system failed by lower driver with %08x.\n",\r
501                         p_irp->IoStatus.Status) );\r
502                 return STATUS_SUCCESS;\r
503         }\r
504 \r
505         state.DeviceState = \r
506                 p_ext->po_state[p_io_stack->Parameters.Power.State.SystemState];\r
507 \r
508         /*\r
509          * Send a device power IRP to our devnode.  Using our device object will\r
510          * only work on win2k and other NT based systems.\r
511          */\r
512         status = PoRequestPowerIrp( p_dev_obj, IRP_MN_SET_POWER, state,\r
513                 __request_power_completion, p_irp, NULL );\r
514 \r
515         if( !NT_SUCCESS( p_irp->IoStatus.Status ) )\r
516         {\r
517                 PoStartNextPowerIrp( p_irp );\r
518                 /* Propagate the failure. */\r
519                 p_irp->IoStatus.Status = status;\r
520                 IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
521                 IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
522                 IOU_PRINT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
523                         ("PoRequestPowerIrp returned %08x.\n", status) );\r
524         }\r
525 \r
526         IOU_EXIT( IOU_DBG_PNP );\r
527         return STATUS_MORE_PROCESSING_REQUIRED;\r
528 }\r
529 \r
530 \r
531 static NTSTATUS\r
532 __fdo_set_power(\r
533         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
534         IN                              IRP* const                                      p_irp,\r
535                 OUT                     cl_irp_action_t* const          p_action )\r
536 {\r
537         NTSTATUS                        status;\r
538         IO_STACK_LOCATION       *p_io_stack;\r
539         iou_fdo_ext_t           *p_ext;\r
540 \r
541         IOU_ENTER( IOU_DBG_POWER );\r
542 \r
543         p_ext = p_dev_obj->DeviceExtension;\r
544         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
545 \r
546         switch( p_io_stack->Parameters.Power.Type )\r
547         {\r
548         case SystemPowerState:\r
549                 /*\r
550                  * Process on the way up the stack.  We cannot block since the \r
551                  * power dispatch function can be called at elevated IRQL if the\r
552                  * device is in a paging/hibernation/crash dump path.\r
553                  */\r
554                 IoMarkIrpPending( p_irp );\r
555                 IoCopyCurrentIrpStackLocationToNext( p_irp );\r
556 #pragma warning( push, 3 )\r
557                 IoSetCompletionRoutine( p_irp, __set_power_completion, NULL, \r
558                         TRUE, TRUE, TRUE );\r
559 #pragma warning( pop )\r
560                 PoCallDriver( p_ext->cl_ext.p_next_do, p_irp );\r
561 \r
562                 *p_action = IrpDoNothing;\r
563                 status = STATUS_PENDING;\r
564                 break;\r
565 \r
566         case DevicePowerState:\r
567         default:\r
568                 /* Pass down and let the PDO driver handle it. */\r
569                 *p_action = IrpIgnore;\r
570                 status = STATUS_SUCCESS;\r
571                 break;\r
572         }\r
573 \r
574         IOU_EXIT( IOU_DBG_POWER );\r
575         return status;\r
576 }\r
577 \r
578 \r
579 void\r
580 update_relations(\r
581         IN                              cl_qlist_t*     const                   p_pdo_list,\r
582         IN      OUT                     DEVICE_RELATIONS* const         p_rel )\r
583 {\r
584         cl_list_item_t  *p_list_item;\r
585         iou_pdo_ext_t   *p_pdo_ext;\r
586 \r
587         IOU_ENTER( IOU_DBG_PNP );\r
588 \r
589         p_list_item = cl_qlist_head( p_pdo_list );\r
590         while( p_list_item != cl_qlist_end( p_pdo_list ) )\r
591         {\r
592                 p_pdo_ext = PARENT_STRUCT( p_list_item, iou_pdo_ext_t, list_item );\r
593 \r
594                 /* Move the list item to the next object. */\r
595                 p_list_item = cl_qlist_next( p_list_item );\r
596 \r
597                 if( !p_pdo_ext->b_present )\r
598                 {\r
599                         /*\r
600                          * We don't report a PDO that is no longer present.  This is how\r
601                          * the PDO will get cleaned up.\r
602                          */\r
603                         p_pdo_ext->b_reported_missing = TRUE;\r
604                         continue;\r
605                 }\r
606                 p_rel->Objects[p_rel->Count] = p_pdo_ext->cl_ext.p_pdo;\r
607                 ObReferenceObject( p_rel->Objects[p_rel->Count++] );\r
608         }\r
609 \r
610         IOU_EXIT( IOU_DBG_PNP );\r
611 }\r