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