[bus_pnp] Move bus PnP IRP handling into bus_pnp
[people/sha0/winvblock.git] / src / bus_pnp.c
1 /**
2  * Copyright (C) 2009, Shao Miller <shao.miller@yrdsb.edu.on.ca>.
3  * Copyright 2006-2008, V.
4  * For WinAoE contact information, see http://winaoe.org/
5  *
6  * This file is part of WinVBlock, derived from WinAoE.
7  *
8  * WinVBlock is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * WinVBlock is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with WinVBlock.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22 /**
23  * @file
24  *
25  * Bus PnP IRP handling
26  *
27  */
28
29 #include <ntddk.h>
30
31 #include "winvblock.h"
32 #include "portable.h"
33 #include "irp.h"
34 #include "driver.h"
35 #include "disk.h"
36 #include "bus.h"
37 #include "debug.h"
38
39 static NTSTATUS STDCALL
40 Bus_IoCompletionRoutine (
41   IN PDEVICE_OBJECT DeviceObject,
42   IN PIRP Irp,
43   IN PKEVENT Event
44  )
45 {
46   KeSetEvent ( Event, 0, FALSE );
47   return STATUS_MORE_PROCESSING_REQUIRED;
48 }
49
50 irp__handler_decl ( bus_pnp__start_dev )
51 {
52   NTSTATUS status;
53   KEVENT event;
54   bus__type_ptr bus_ptr;
55
56   bus_ptr = get_bus_ptr ( DeviceExtension );
57   KeInitializeEvent ( &event, NotificationEvent, FALSE );
58   IoCopyCurrentIrpStackLocationToNext ( Irp );
59   IoSetCompletionRoutine ( Irp,
60                            ( PIO_COMPLETION_ROUTINE ) Bus_IoCompletionRoutine,
61                            ( PVOID ) & event, TRUE, TRUE, TRUE );
62   status = IoCallDriver ( bus_ptr->LowerDeviceObject, Irp );
63   if ( status == STATUS_PENDING )
64     {
65       DBG ( "Locked\n" );
66       KeWaitForSingleObject ( &event, Executive, KernelMode, FALSE, NULL );
67     }
68   if ( NT_SUCCESS ( status = Irp->IoStatus.Status ) )
69     {
70       DeviceExtension->OldState = DeviceExtension->State;
71       DeviceExtension->State = Started;
72     }
73   status = STATUS_SUCCESS;
74   Irp->IoStatus.Status = status;
75   IoCompleteRequest ( Irp, IO_NO_INCREMENT );
76   *completion_ptr = TRUE;
77   return status;
78 }
79
80 irp__handler_decl ( bus_pnp__remove_dev )
81 {
82   NTSTATUS status;
83   bus__type_ptr bus_ptr;
84   disk__type_ptr walker,
85    next;
86
87   DeviceExtension->OldState = DeviceExtension->State;
88   DeviceExtension->State = Deleted;
89   Irp->IoStatus.Information = 0;
90   Irp->IoStatus.Status = STATUS_SUCCESS;
91   IoSkipCurrentIrpStackLocation ( Irp );
92   bus_ptr = get_bus_ptr ( DeviceExtension );
93   status = IoCallDriver ( bus_ptr->LowerDeviceObject, Irp );
94   walker = ( disk__type_ptr ) bus_ptr->first_child_ptr;
95   while ( walker != NULL )
96     {
97       next = walker->next_sibling_ptr;
98       IoDeleteDevice ( walker->dev_ext_ptr->Self );
99       walker = next;
100     }
101   bus_ptr->Children = 0;
102   bus_ptr->first_child_ptr = NULL;
103   IoDetachDevice ( bus_ptr->LowerDeviceObject );
104   IoDeleteDevice ( DeviceExtension->Self );
105   *completion_ptr = TRUE;
106   return status;
107 }
108
109 irp__handler_decl ( bus_pnp__query_dev_relations )
110 {
111   NTSTATUS status;
112   bus__type_ptr bus_ptr;
113   ULONG count;
114   disk__type_ptr walker;
115   PDEVICE_RELATIONS dev_relations;
116
117   bus_ptr = get_bus_ptr ( DeviceExtension );
118   if ( Stack->Parameters.QueryDeviceRelations.Type != BusRelations
119        || Irp->IoStatus.Information )
120     {
121       status = Irp->IoStatus.Status;
122       IoSkipCurrentIrpStackLocation ( Irp );
123       status = IoCallDriver ( bus_ptr->LowerDeviceObject, Irp );
124       *completion_ptr = TRUE;
125       return status;
126     }
127   count = 0;
128   walker = ( disk__type_ptr ) bus_ptr->first_child_ptr;
129   while ( walker != NULL )
130     {
131       count++;
132       walker = walker->next_sibling_ptr;
133     }
134   dev_relations =
135     ( PDEVICE_RELATIONS ) ExAllocatePool ( NonPagedPool,
136                                            sizeof ( DEVICE_RELATIONS ) +
137                                            ( sizeof ( PDEVICE_OBJECT ) *
138                                              count ) );
139   if ( dev_relations == NULL )
140     {
141       Irp->IoStatus.Information = 0;
142       status = STATUS_INSUFFICIENT_RESOURCES;
143       Irp->IoStatus.Status = status;
144       IoSkipCurrentIrpStackLocation ( Irp );
145       status = IoCallDriver ( bus_ptr->LowerDeviceObject, Irp );
146       *completion_ptr = TRUE;
147       return status;
148     }
149   dev_relations->Count = count;
150
151   count = 0;
152   walker = ( disk__type_ptr ) bus_ptr->first_child_ptr;
153   while ( walker != NULL )
154     {
155       ObReferenceObject ( walker->dev_ext_ptr->Self );
156       dev_relations->Objects[count] = walker->dev_ext_ptr->Self;
157       count++;
158       walker = walker->next_sibling_ptr;
159     }
160   Irp->IoStatus.Information = ( ULONG_PTR ) dev_relations;
161   status = STATUS_SUCCESS;
162   Irp->IoStatus.Status = status;
163   IoSkipCurrentIrpStackLocation ( Irp );
164   status = IoCallDriver ( bus_ptr->LowerDeviceObject, Irp );
165   *completion_ptr = TRUE;
166   return status;
167 }
168
169 irp__handler_decl ( bus_pnp__simple )
170 {
171   NTSTATUS status;
172   bus__type_ptr bus_ptr;
173
174   bus_ptr = get_bus_ptr ( DeviceExtension );
175   switch ( Stack->MinorFunction )
176     {
177       case IRP_MN_QUERY_PNP_DEVICE_STATE:
178         Irp->IoStatus.Information = 0;
179         status = STATUS_SUCCESS;
180         break;
181       case IRP_MN_QUERY_STOP_DEVICE:
182         DeviceExtension->OldState = DeviceExtension->State;
183         DeviceExtension->State = StopPending;
184         status = STATUS_SUCCESS;
185         break;
186       case IRP_MN_CANCEL_STOP_DEVICE:
187         DeviceExtension->State = DeviceExtension->OldState;
188         status = STATUS_SUCCESS;
189         break;
190       case IRP_MN_STOP_DEVICE:
191         DeviceExtension->OldState = DeviceExtension->State;
192         DeviceExtension->State = Stopped;
193         status = STATUS_SUCCESS;
194         break;
195       case IRP_MN_QUERY_REMOVE_DEVICE:
196         DeviceExtension->OldState = DeviceExtension->State;
197         DeviceExtension->State = RemovePending;
198         status = STATUS_SUCCESS;
199         break;
200       case IRP_MN_CANCEL_REMOVE_DEVICE:
201         DeviceExtension->State = DeviceExtension->OldState;
202         status = STATUS_SUCCESS;
203         break;
204       case IRP_MN_SURPRISE_REMOVAL:
205         DeviceExtension->OldState = DeviceExtension->State;
206         DeviceExtension->State = SurpriseRemovePending;
207         status = STATUS_SUCCESS;
208         break;
209       default:
210         status = Irp->IoStatus.Status;
211     }
212
213   Irp->IoStatus.Status = status;
214   IoSkipCurrentIrpStackLocation ( Irp );
215   status = IoCallDriver ( bus_ptr->LowerDeviceObject, Irp );
216   *completion_ptr = TRUE;
217   return status;
218 }