[project] Rename winvblock__uint32 back to UINT32
[people/sha0/winvblock.git] / src / winvblock / bus / pnp.c
1 /**
2  * Copyright (C) 2009-2011, 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 <stdio.h>
29 #include <ntddk.h>
30 #include <initguid.h>
31
32 #include "winvblock.h"
33 #include "wv_stdlib.h"
34 #include "portable.h"
35 #include "driver.h"
36 #include "bus.h"
37 #include "debug.h"
38 #include "probe.h"
39
40 static NTSTATUS STDCALL WvBusPnpIoCompletion_(
41     IN PDEVICE_OBJECT dev_obj,
42     IN PIRP irp,
43     IN PKEVENT event
44   ) {
45     KeSetEvent(event, 0, FALSE);
46     return STATUS_MORE_PROCESSING_REQUIRED;
47   }
48
49 static NTSTATUS STDCALL WvBusPnpStartDev_(IN WVL_SP_BUS_T bus, IN PIRP irp) {
50     NTSTATUS status;
51     KEVENT event;
52     PDEVICE_OBJECT lower = bus->LowerDeviceObject;
53
54     if (!lower)
55       return driver__complete_irp(irp, 0, STATUS_SUCCESS);
56     KeInitializeEvent(&event, NotificationEvent, FALSE);
57     IoCopyCurrentIrpStackLocationToNext(irp);
58     IoSetCompletionRoutine(
59         irp,
60         (PIO_COMPLETION_ROUTINE) WvBusPnpIoCompletion_,
61         (void *) &event,
62         TRUE,
63         TRUE,
64         TRUE
65       );
66     status = IoCallDriver(lower, irp);
67     if (status == STATUS_PENDING) {
68         DBG("Locked\n");
69         KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
70       }
71     if (NT_SUCCESS(status = irp->IoStatus.Status)) {
72         bus->OldState = bus->State;
73         bus->State = WvlBusStateStarted;
74       }
75     return driver__complete_irp(
76         irp,
77         irp->IoStatus.Information,
78         STATUS_SUCCESS
79       );
80   }
81
82 static NTSTATUS STDCALL WvBusPnpRemoveDev_(IN WVL_SP_BUS_T bus, IN PIRP irp) {
83     PIO_STACK_LOCATION io_stack_loc = IoGetCurrentIrpStackLocation(irp);
84     NTSTATUS status;
85     PDEVICE_OBJECT lower;
86     PLIST_ENTRY node_link;
87
88     if (!(io_stack_loc->Control & SL_PENDING_RETURNED)) {
89         /* Enqueue the IRP. */
90         status = WvBusEnqueueIrp(bus, irp);
91         if (status != STATUS_PENDING)
92           /* Problem. */
93           return driver__complete_irp(irp, 0, status);
94         /* Ok. */
95         return status;
96       }
97     /* If we get here, we should be called by WvBusProcessWorkItems() */
98     status = STATUS_SUCCESS;
99     lower = bus->LowerDeviceObject;
100     bus->OldState = bus->State;
101     bus->State = WvlBusStateDeleted;
102     /* Pass the IRP on to any lower DEVICE_OBJECT */
103     if (lower) {
104         irp->IoStatus.Information = 0;
105         irp->IoStatus.Status = STATUS_SUCCESS;
106         IoSkipCurrentIrpStackLocation(irp);
107         status = IoCallDriver(lower, irp);
108       }
109     /* Remove all children. */
110     node_link = &bus->BusPrivate_.Nodes;
111     while ((node_link = node_link->Flink) != &bus->BusPrivate_.Nodes) {
112         WVL_SP_BUS_NODE node = CONTAINING_RECORD(
113             node_link,
114             WVL_S_BUS_NODE,
115             BusPrivate_.Link
116           );
117
118         DBG("Removing PDO from bus...\n");
119         RemoveEntryList(&node->BusPrivate_.Link);
120         ObDereferenceObject(node->BusPrivate_.Pdo);
121         bus->BusPrivate_.NodeCount--;
122       }
123     /* Detach from any lower DEVICE_OBJECT */
124     if (lower)
125       IoDetachDevice(lower);
126     /* Delete. */
127     IoDeleteDevice(bus->Fdo);
128     /* Stop the thread. */
129     bus->Stop = TRUE;
130     return status;
131   }
132
133 static NTSTATUS STDCALL WvBusPnpQueryDevRelations_(
134     IN WVL_SP_BUS_T bus,
135     IN PIRP irp
136   ) {
137     NTSTATUS status;
138     PDEVICE_OBJECT lower = bus->LowerDeviceObject;
139     PIO_STACK_LOCATION io_stack_loc = IoGetCurrentIrpStackLocation(irp);
140     UINT32 i;
141     PDEVICE_RELATIONS dev_relations;
142     PLIST_ENTRY node_link;
143
144     if (!(io_stack_loc->Control & SL_PENDING_RETURNED)) {
145         /* Enqueue the IRP. */
146         status = WvBusEnqueueIrp(bus, irp);
147         if (status != STATUS_PENDING)
148           /* Problem. */
149           return driver__complete_irp(irp, 0, status);
150         /* Ok. */
151         return status;
152       }
153     /* If we get here, we should be called by WvBusProcessWorkItems() */
154     if (
155         io_stack_loc->Parameters.QueryDeviceRelations.Type != BusRelations ||
156         irp->IoStatus.Information
157       ) {
158         if (lower) {
159             IoSkipCurrentIrpStackLocation(irp);
160             return IoCallDriver(lower, irp);
161           }
162         return driver__complete_irp(
163             irp,
164             irp->IoStatus.Information,
165             irp->IoStatus.Status
166           );
167       }
168     WvProbeDisks();
169     dev_relations = wv_malloc(
170         sizeof *dev_relations +
171           (sizeof (PDEVICE_OBJECT) * bus->BusPrivate_.NodeCount)
172       );
173     if (dev_relations == NULL) {
174         /* Couldn't allocate dev_relations, but silently succeed. */
175         if (lower) {
176             IoSkipCurrentIrpStackLocation(irp);
177             return IoCallDriver(lower, irp);
178           }
179         return driver__complete_irp(irp, 0, STATUS_SUCCESS);
180       }
181     dev_relations->Count = bus->BusPrivate_.NodeCount;
182
183     i = 0;
184     node_link = &bus->BusPrivate_.Nodes;
185     while ((node_link = node_link->Flink) != &bus->BusPrivate_.Nodes) {
186         WVL_SP_BUS_NODE node = CONTAINING_RECORD(
187             node_link,
188             WVL_S_BUS_NODE,
189             BusPrivate_.Link
190           );
191
192         dev_relations->Objects[i] = node->BusPrivate_.Pdo;
193         i++;
194       }
195     irp->IoStatus.Information = (ULONG_PTR) dev_relations;
196     irp->IoStatus.Status = status = STATUS_SUCCESS;
197     if (lower) {
198         IoSkipCurrentIrpStackLocation(irp);
199         return IoCallDriver(lower, irp);
200       }
201     return driver__complete_irp(irp, irp->IoStatus.Information, status);
202   }
203
204 static NTSTATUS STDCALL WvBusPnpQueryCapabilities_(
205     IN WVL_SP_BUS_T bus,
206     IN PIRP irp
207   ) {
208     PIO_STACK_LOCATION io_stack_loc = IoGetCurrentIrpStackLocation(irp);
209     PDEVICE_CAPABILITIES DeviceCapabilities =
210       io_stack_loc->Parameters.DeviceCapabilities.Capabilities;
211     NTSTATUS status;
212     DEVICE_CAPABILITIES ParentDeviceCapabilities;
213     PDEVICE_OBJECT lower;
214
215     if (DeviceCapabilities->Version != 1 ||
216         DeviceCapabilities->Size < sizeof (DEVICE_CAPABILITIES)
217       )
218       return driver__complete_irp(irp, 0, STATUS_UNSUCCESSFUL);
219     /* Let the lower DEVICE_OBJECT handle the IRP. */
220     lower = bus->LowerDeviceObject;
221     IoSkipCurrentIrpStackLocation(irp);
222     return IoCallDriver(lower, irp);
223   }
224
225 DEFINE_GUID(
226     GUID_BUS_TYPE_INTERNAL,
227     0x2530ea73L,
228     0x086b,
229     0x11d1,
230     0xa0,
231     0x9f,
232     0x00,
233     0xc0,
234     0x4f,
235     0xc3,
236     0x40,
237     0xb1
238   );
239
240 static NTSTATUS STDCALL WvBusPnpQueryBusInfo_(IN WVL_SP_BUS_T bus, IN PIRP irp) {
241     PPNP_BUS_INFORMATION pnp_bus_info;
242     NTSTATUS status;
243
244     pnp_bus_info = wv_palloc(sizeof *pnp_bus_info);
245     if (pnp_bus_info == NULL) {
246         DBG("wv_palloc IRP_MN_QUERY_BUS_INFORMATION\n");
247         status = STATUS_INSUFFICIENT_RESOURCES;
248         goto alloc_pnp_bus_info;
249       }
250     pnp_bus_info->BusTypeGuid = GUID_BUS_TYPE_INTERNAL;
251     pnp_bus_info->LegacyBusType = PNPBus;
252     pnp_bus_info->BusNumber = 0;
253     irp->IoStatus.Information = (ULONG_PTR) pnp_bus_info;
254     status = STATUS_SUCCESS;
255
256     /* irp-IoStatus.Information (pnp_bus_info) not freed. */
257     alloc_pnp_bus_info:
258
259     irp->IoStatus.Status = status;
260     IoCompleteRequest(irp, IO_NO_INCREMENT);
261     return status;
262   }
263
264 static NTSTATUS STDCALL WvBusPnpSimple_(
265     IN WVL_SP_BUS_T bus,
266     IN PIRP irp,
267     IN UCHAR code
268   ) {
269     NTSTATUS status;
270     PDEVICE_OBJECT lower = bus->LowerDeviceObject;
271
272     switch (code) {
273         case IRP_MN_QUERY_PNP_DEVICE_STATE:
274           DBG("bus_pnp: IRP_MN_QUERY_PNP_DEVICE_STATE\n");
275           irp->IoStatus.Information = 0;
276           status = STATUS_SUCCESS;
277           break;
278
279         case IRP_MN_QUERY_STOP_DEVICE:
280           DBG("bus_pnp: IRP_MN_QUERY_STOP_DEVICE\n");
281           bus->OldState = bus->State;
282           bus->State = WvlBusStateStopPending;
283           status = STATUS_SUCCESS;
284           break;
285
286         case IRP_MN_CANCEL_STOP_DEVICE:
287           DBG("bus_pnp: IRP_MN_CANCEL_STOP_DEVICE\n");
288           bus->State = bus->OldState;
289           status = STATUS_SUCCESS;
290           break;
291
292         case IRP_MN_STOP_DEVICE:
293           DBG("bus_pnp: IRP_MN_STOP_DEVICE\n");
294           bus->OldState = bus->State;
295           bus->State = WvlBusStateStopped;
296           status = STATUS_SUCCESS;
297           break;
298
299         case IRP_MN_QUERY_REMOVE_DEVICE:
300           DBG("bus_pnp: IRP_MN_QUERY_REMOVE_DEVICE\n");
301           bus->OldState = bus->State;
302           bus->State = WvlBusStateRemovePending;
303           status = STATUS_SUCCESS;
304           break;
305
306         case IRP_MN_CANCEL_REMOVE_DEVICE:
307           DBG("bus_pnp: IRP_MN_CANCEL_REMOVE_DEVICE\n");
308           bus->State = bus->OldState;
309           status = STATUS_SUCCESS;
310           break;
311
312         case IRP_MN_SURPRISE_REMOVAL:
313           DBG("bus_pnp: IRP_MN_SURPRISE_REMOVAL\n");
314           bus->OldState = bus->State;
315           bus->State = WvlBusStateSurpriseRemovePending;
316           status = STATUS_SUCCESS;
317           break;
318
319         case IRP_MN_QUERY_RESOURCES:
320         case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
321           DBG("bus_pnp: IRP_MN_QUERY_RESOURCE*\n");
322           IoCompleteRequest(irp, IO_NO_INCREMENT);
323           return STATUS_SUCCESS;
324           
325         default:
326           DBG("bus_pnp: Unhandled IRP_MN_*: %d\n", code);
327           status = irp->IoStatus.Status;
328       }
329
330     irp->IoStatus.Status = status;
331     if (lower) {
332         IoSkipCurrentIrpStackLocation(irp);
333         return IoCallDriver(lower, irp);
334       }
335     return driver__complete_irp(irp, irp->IoStatus.Information, status);
336   }
337
338 /* Bus PnP dispatch routine. */
339 WVL_M_LIB NTSTATUS STDCALL WvBusPnp(
340     IN WVL_SP_BUS_T bus,
341     IN PIRP irp,
342     IN UCHAR code
343   ) {
344     switch (code) {
345         case IRP_MN_QUERY_DEVICE_TEXT:
346           DBG("bus_pnp: IRP_MN_QUERY_DEVICE_TEXT\n");
347           return bus->QueryDevText(bus, irp);
348
349         case IRP_MN_QUERY_BUS_INFORMATION:
350           DBG("bus_pnp: IRP_MN_QUERY_BUS_INFORMATION\n");
351           return WvBusPnpQueryBusInfo_(bus, irp);
352
353         case IRP_MN_QUERY_DEVICE_RELATIONS:
354           DBG("bus_pnp: IRP_MN_QUERY_DEVICE_RELATIONS\n");
355           return WvBusPnpQueryDevRelations_(bus, irp);
356
357         case IRP_MN_QUERY_CAPABILITIES:
358           DBG("bus_pnp: IRP_MN_QUERY_CAPABILITIES\n");
359           return WvBusPnpQueryCapabilities_(bus, irp);
360
361         case IRP_MN_REMOVE_DEVICE:
362           DBG("bus_pnp: IRP_MN_REMOVE_DEVICE\n");
363           return WvBusPnpRemoveDev_(bus, irp);
364
365         case IRP_MN_START_DEVICE:
366           DBG("bus_pnp: IRP_MN_START_DEVICE\n");
367           return WvBusPnpStartDev_(bus, irp);
368
369         default:
370           return WvBusPnpSimple_(bus, irp, code);
371       }
372   }