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