d9e50fa0b17ca4a5e696122f889d03fa90abbeca
[people/sha0/winvblock.git] / src / winvblock / bus / pnp.c
1 /**
2  * Copyright (C) 2009-2010, 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 #include <ntddk.h>
29
30 #include "winvblock.h"
31 #include "wv_stdlib.h"
32 #include "portable.h"
33 #include "irp.h"
34 #include "driver.h"
35 #include "device.h"
36 #include "disk.h"
37 #include "bus.h"
38 #include "debug.h"
39 #include "probe.h"
40
41 static NTSTATUS STDCALL
42 Bus_IoCompletionRoutine (
43   IN PDEVICE_OBJECT DeviceObject,
44   IN PIRP Irp,
45   IN PKEVENT Event
46  )
47 {
48   KeSetEvent ( Event, 0, FALSE );
49   return STATUS_MORE_PROCESSING_REQUIRED;
50 }
51
52 NTSTATUS STDCALL bus_pnp__start_dev(
53     IN PDEVICE_OBJECT DeviceObject,
54     IN PIRP Irp,
55     IN PIO_STACK_LOCATION Stack,
56     IN struct device__type * dev_ptr,
57     OUT winvblock__bool_ptr completion_ptr
58   )
59 {
60   NTSTATUS status;
61   KEVENT event;
62   struct bus__type * bus_ptr = bus__get(dev_ptr);
63   PDEVICE_OBJECT lower = bus_ptr->LowerDeviceObject;
64
65   if (!lower) {
66       *completion_ptr = TRUE;
67       return STATUS_SUCCESS;
68     }
69   KeInitializeEvent ( &event, NotificationEvent, FALSE );
70   IoCopyCurrentIrpStackLocationToNext ( Irp );
71   IoSetCompletionRoutine ( Irp,
72                            ( PIO_COMPLETION_ROUTINE ) Bus_IoCompletionRoutine,
73                            ( void * )&event, TRUE, TRUE, TRUE );
74   status = IoCallDriver ( lower, Irp );
75   if ( status == STATUS_PENDING )
76     {
77       DBG ( "Locked\n" );
78       KeWaitForSingleObject ( &event, Executive, KernelMode, FALSE, NULL );
79     }
80   if ( NT_SUCCESS ( status = Irp->IoStatus.Status ) )
81     {
82       dev_ptr->old_state = dev_ptr->state;
83       dev_ptr->state = device__state_started;
84     }
85   status = STATUS_SUCCESS;
86   Irp->IoStatus.Status = status;
87   IoCompleteRequest ( Irp, IO_NO_INCREMENT );
88   *completion_ptr = TRUE;
89   return status;
90 }
91
92 NTSTATUS STDCALL bus_pnp__remove_dev(
93     IN PDEVICE_OBJECT DeviceObject,
94     IN PIRP Irp,
95     IN PIO_STACK_LOCATION Stack,
96     IN struct device__type * dev_ptr,
97     OUT winvblock__bool_ptr completion_ptr
98   )
99 {
100   NTSTATUS status;
101   struct bus__type * bus_ptr;
102   struct device__type * walker, * next;
103   PDEVICE_OBJECT lower;
104
105   dev_ptr->old_state = dev_ptr->state;
106   dev_ptr->state = device__state_deleted;
107   Irp->IoStatus.Information = 0;
108   Irp->IoStatus.Status = STATUS_SUCCESS;
109   IoSkipCurrentIrpStackLocation ( Irp );
110   bus_ptr = bus__get(dev_ptr);
111   status = IoCallDriver ( bus_ptr->LowerDeviceObject, Irp );
112   walker = bus_ptr->first_child;
113   while ( walker != NULL )
114     {
115       next = walker->next_sibling_ptr;
116       device__close ( walker );
117       IoDeleteDevice ( walker->Self );
118       device__free ( walker );
119       walker = next;
120     }
121   bus_ptr->Children = 0;
122   bus_ptr->first_child = NULL;
123   lower = bus_ptr->LowerDeviceObject;
124   if (lower)
125     IoDetachDevice(lower);
126   IoDeleteDevice ( dev_ptr->Self );
127   device__free ( dev_ptr );
128   *completion_ptr = TRUE;
129   return status;
130 }
131
132 NTSTATUS STDCALL bus_pnp__query_dev_relations(
133     IN PDEVICE_OBJECT DeviceObject,
134     IN PIRP Irp,
135     IN PIO_STACK_LOCATION Stack,
136     IN struct device__type * dev_ptr,
137     OUT winvblock__bool_ptr completion_ptr
138   )
139 {
140   NTSTATUS status;
141   struct bus__type * bus_ptr;
142   winvblock__uint32 count;
143   struct device__type * walker;
144   PDEVICE_RELATIONS dev_relations;
145   PDEVICE_OBJECT lower;
146
147   bus_ptr = bus__get(dev_ptr);
148   lower = bus_ptr->LowerDeviceObject;
149   if ( Stack->Parameters.QueryDeviceRelations.Type != BusRelations
150        || Irp->IoStatus.Information )
151     {
152       status = Irp->IoStatus.Status;
153       if (lower) {
154           IoSkipCurrentIrpStackLocation(Irp);
155           status = IoCallDriver(lower, Irp);
156         }
157       *completion_ptr = TRUE;
158       return status;
159     }
160   probe__disks (  );
161   count = 0;
162   walker = bus_ptr->first_child;
163   while ( walker != NULL )
164     {
165       count++;
166       walker = walker->next_sibling_ptr;
167     }
168   dev_relations = wv_malloc(
169       sizeof *dev_relations + (sizeof (PDEVICE_OBJECT) * count)
170     );
171   if ( dev_relations == NULL )
172     {
173       Irp->IoStatus.Information = 0;
174       status = STATUS_SUCCESS;
175       Irp->IoStatus.Status = status;
176       if (lower) {
177           IoSkipCurrentIrpStackLocation ( Irp );
178           status = IoCallDriver(lower, Irp);
179         }
180       *completion_ptr = TRUE;
181       return status;
182     }
183   dev_relations->Count = count;
184
185   count = 0;
186   walker = bus_ptr->first_child;
187   while ( walker != NULL )
188     {
189       ObReferenceObject ( walker->Self );
190       dev_relations->Objects[count] = walker->Self;
191       count++;
192       walker = walker->next_sibling_ptr;
193     }
194   Irp->IoStatus.Information = ( ULONG_PTR ) dev_relations;
195   status = STATUS_SUCCESS;
196   Irp->IoStatus.Status = status;
197   if (lower) {
198       IoSkipCurrentIrpStackLocation ( Irp );
199       status = IoCallDriver(lower, Irp);
200     }
201   *completion_ptr = TRUE;
202   return status;
203 }
204
205 NTSTATUS STDCALL bus_pnp__simple(
206     IN PDEVICE_OBJECT DeviceObject,
207     IN PIRP Irp,
208     IN PIO_STACK_LOCATION Stack,
209     IN struct device__type * dev_ptr,
210     OUT winvblock__bool_ptr completion_ptr
211   )
212 {
213   NTSTATUS status;
214   struct bus__type * bus_ptr;
215   PDEVICE_OBJECT lower;
216
217   bus_ptr = bus__get(dev_ptr);
218   lower = bus_ptr->LowerDeviceObject;
219   switch ( Stack->MinorFunction )
220     {
221       case IRP_MN_QUERY_PNP_DEVICE_STATE:
222         Irp->IoStatus.Information = 0;
223         status = STATUS_SUCCESS;
224         break;
225       case IRP_MN_QUERY_STOP_DEVICE:
226         dev_ptr->old_state = dev_ptr->state;
227         dev_ptr->state = device__state_stop_pending;
228         status = STATUS_SUCCESS;
229         break;
230       case IRP_MN_CANCEL_STOP_DEVICE:
231         dev_ptr->state = dev_ptr->old_state;
232         status = STATUS_SUCCESS;
233         break;
234       case IRP_MN_STOP_DEVICE:
235         dev_ptr->old_state = dev_ptr->state;
236         dev_ptr->state = device__state_stopped;
237         status = STATUS_SUCCESS;
238         break;
239       case IRP_MN_QUERY_REMOVE_DEVICE:
240         dev_ptr->old_state = dev_ptr->state;
241         dev_ptr->state = device__state_remove_pending;
242         status = STATUS_SUCCESS;
243         break;
244       case IRP_MN_CANCEL_REMOVE_DEVICE:
245         dev_ptr->state = dev_ptr->old_state;
246         status = STATUS_SUCCESS;
247         break;
248       case IRP_MN_SURPRISE_REMOVAL:
249         dev_ptr->old_state = dev_ptr->state;
250         dev_ptr->state = device__state_surprise_remove_pending;
251         status = STATUS_SUCCESS;
252         break;
253       default:
254         status = Irp->IoStatus.Status;
255     }
256
257   Irp->IoStatus.Status = status;
258   if (lower) {
259       IoSkipCurrentIrpStackLocation(Irp);
260       status = IoCallDriver(lower, Irp);
261     }
262   *completion_ptr = TRUE;
263   return status;
264 }