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