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/
6 * This file is part of WinVBlock, derived from WinAoE.
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.
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.
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/>.
25 * Bus PnP IRP handling.
32 #include "winvblock.h"
33 #include "wv_stdlib.h"
42 static NTSTATUS STDCALL WvBusPnpIoCompletion_(
43 IN PDEVICE_OBJECT dev_obj,
47 KeSetEvent(event, 0, FALSE);
48 return STATUS_MORE_PROCESSING_REQUIRED;
51 static NTSTATUS STDCALL WvBusPnpStartDev_(IN WV_SP_BUS_T bus, IN PIRP irp) {
54 PDEVICE_OBJECT lower = bus->LowerDeviceObject;
57 return driver__complete_irp(irp, 0, STATUS_SUCCESS);
58 KeInitializeEvent(&event, NotificationEvent, FALSE);
59 IoCopyCurrentIrpStackLocationToNext(irp);
60 IoSetCompletionRoutine(
62 (PIO_COMPLETION_ROUTINE) WvBusPnpIoCompletion_,
68 status = IoCallDriver(lower, irp);
69 if (status == STATUS_PENDING) {
71 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
73 if (NT_SUCCESS(status = irp->IoStatus.Status)) {
74 bus->Dev.OldState = bus->Dev.State;
75 bus->Dev.State = WvDevStateStarted;
77 return driver__complete_irp(
79 irp->IoStatus.Information,
84 static NTSTATUS STDCALL WvBusPnpRemoveDev_(IN WV_SP_BUS_T bus, IN PIRP irp) {
85 PIO_STACK_LOCATION io_stack_loc = IoGetCurrentIrpStackLocation(irp);
88 WV_SP_DEV_T dev = &bus->Dev;
89 WV_SP_DEV_T walker, next;
90 PLIST_ENTRY node_link;
92 if (!(io_stack_loc->Control & SL_PENDING_RETURNED)) {
93 /* Enqueue the IRP. */
94 status = WvBusEnqueueIrp(bus, irp);
95 if (status != STATUS_PENDING)
97 return driver__complete_irp(irp, 0, status);
101 /* If we get here, we should be called by WvBusProcessWorkItems() */
102 status = STATUS_SUCCESS;
103 lower = bus->LowerDeviceObject;
104 dev->OldState = dev->State;
105 dev->State = WvDevStateDeleted;
106 /* Pass the IRP on to any lower DEVICE_OBJECT */
108 irp->IoStatus.Information = 0;
109 irp->IoStatus.Status = STATUS_SUCCESS;
110 IoSkipCurrentIrpStackLocation(irp);
111 status = IoCallDriver(lower, irp);
113 /* Remove all children. */
114 walker = bus->first_child;
115 while (walker != NULL) {
116 next = walker->next_sibling_ptr;
118 IoDeleteDevice(walker->Self);
122 node_link = &bus->BusPrivate_.Nodes;
123 while ((node_link = node_link->Flink) != &bus->BusPrivate_.Nodes) {
124 WV_SP_BUS_NODE node = CONTAINING_RECORD(
130 DBG("Removing PDO from bus...\n");
131 RemoveEntryList(&node->BusPrivate_.Link);
132 ObDereferenceObject(node->BusPrivate_.Pdo);
133 bus->BusPrivate_.NodeCount--;
135 /* Somewhat redundant, since the bus will be freed shortly. */
137 bus->first_child = NULL;
138 /* Detach from any lower DEVICE_OBJECT */
140 IoDetachDevice(lower);
141 /* Delete and free. */
142 IoDeleteDevice(dev->Self);
147 static NTSTATUS STDCALL WvBusPnpQueryDevRelations_(
152 WV_SP_DEV_T dev = &bus->Dev;
153 PDEVICE_OBJECT lower = bus->LowerDeviceObject;
154 PIO_STACK_LOCATION io_stack_loc = IoGetCurrentIrpStackLocation(irp);
155 winvblock__uint32 count;
157 PDEVICE_RELATIONS dev_relations;
158 PLIST_ENTRY node_link;
160 if (!(io_stack_loc->Control & SL_PENDING_RETURNED)) {
161 /* Enqueue the IRP. */
162 status = WvBusEnqueueIrp(bus, irp);
163 if (status != STATUS_PENDING)
165 return driver__complete_irp(irp, 0, status);
169 /* If we get here, we should be called by WvBusProcessWorkItems() */
171 io_stack_loc->Parameters.QueryDeviceRelations.Type != BusRelations ||
172 irp->IoStatus.Information
175 IoSkipCurrentIrpStackLocation(irp);
176 return IoCallDriver(lower, irp);
178 return driver__complete_irp(
180 irp->IoStatus.Information,
186 walker = bus->first_child;
187 while (walker != NULL) {
189 walker = walker->next_sibling_ptr;
191 count += bus->BusPrivate_.NodeCount;
192 dev_relations = wv_malloc(
193 sizeof *dev_relations + (sizeof (PDEVICE_OBJECT) * count)
195 if (dev_relations == NULL) {
196 /* Couldn't allocate dev_relations, but silently succeed. */
198 IoSkipCurrentIrpStackLocation(irp);
199 return IoCallDriver(lower, irp);
201 return driver__complete_irp(irp, 0, STATUS_SUCCESS);
203 dev_relations->Count = count;
206 walker = bus->first_child;
207 while (walker != NULL) {
208 ObReferenceObject(walker->Self);
209 dev_relations->Objects[count] = walker->Self;
211 walker = walker->next_sibling_ptr;
213 node_link = &bus->BusPrivate_.Nodes;
214 while ((node_link = node_link->Flink) != &bus->BusPrivate_.Nodes) {
215 WV_SP_BUS_NODE node = CONTAINING_RECORD(
221 dev_relations->Objects[count] = node->BusPrivate_.Pdo;
224 irp->IoStatus.Information = (ULONG_PTR) dev_relations;
225 irp->IoStatus.Status = status = STATUS_SUCCESS;
227 IoSkipCurrentIrpStackLocation(irp);
228 return IoCallDriver(lower, irp);
230 return driver__complete_irp(irp, irp->IoStatus.Information, status);
233 static NTSTATUS STDCALL WvBusPnpQueryCapabilities_(
237 PIO_STACK_LOCATION io_stack_loc = IoGetCurrentIrpStackLocation(irp);
238 PDEVICE_CAPABILITIES DeviceCapabilities =
239 io_stack_loc->Parameters.DeviceCapabilities.Capabilities;
241 WV_SP_DEV_T dev = &bus->Dev;
242 DEVICE_CAPABILITIES ParentDeviceCapabilities;
243 PDEVICE_OBJECT lower;
245 if (DeviceCapabilities->Version != 1 ||
246 DeviceCapabilities->Size < sizeof (DEVICE_CAPABILITIES)
248 return driver__complete_irp(irp, 0, STATUS_UNSUCCESSFUL);
249 /* If there's a lower DEVICE_OBJECT, let it handle the IRP. */
250 lower = bus->LowerDeviceObject;
252 IoSkipCurrentIrpStackLocation(irp);
253 return IoCallDriver(lower, irp);
255 /* Otherwise, return our parent's capabilities. */
256 status = WvDriverGetDevCapabilities(
260 if (!NT_SUCCESS(status))
261 return driver__complete_irp(irp, 0, status);
262 return driver__complete_irp(irp, irp->IoStatus.Information, STATUS_SUCCESS);
265 static NTSTATUS STDCALL WvBusPnpQueryDevText_(IN WV_SP_BUS_T bus, IN PIRP irp) {
266 WV_SP_DEV_T dev = &bus->Dev;
268 PIO_STACK_LOCATION io_stack_loc = IoGetCurrentIrpStackLocation(irp);
270 winvblock__uint32 str_len;
272 /* Allocate a string buffer. */
273 str = wv_mallocz(sizeof *str);
275 DBG("wv_malloc IRP_MN_QUERY_DEVICE_TEXT\n");
276 status = STATUS_INSUFFICIENT_RESOURCES;
279 /* Determine the query type. */
280 switch (io_stack_loc->Parameters.QueryDeviceText.DeviceTextType) {
281 case DeviceTextDescription:
282 str_len = swprintf(*str, winvblock__literal_w L" Bus") + 1;
283 irp->IoStatus.Information =
284 (ULONG_PTR) wv_palloc(str_len * sizeof *str);
285 if (irp->IoStatus.Information == 0) {
286 DBG("wv_palloc DeviceTextDescription\n");
287 status = STATUS_INSUFFICIENT_RESOURCES;
291 (PWCHAR) irp->IoStatus.Information,
293 str_len * sizeof (WCHAR)
295 status = STATUS_SUCCESS;
298 case DeviceTextLocationInformation:
299 str_len = WvDevPnpId(
304 irp->IoStatus.Information =
305 (ULONG_PTR) wv_palloc(str_len * sizeof *str);
306 if (irp->IoStatus.Information == 0) {
307 DBG("wv_palloc DeviceTextLocationInformation\n");
308 status = STATUS_INSUFFICIENT_RESOURCES;
312 (PWCHAR) irp->IoStatus.Information,
314 str_len * sizeof (WCHAR)
316 status = STATUS_SUCCESS;
320 irp->IoStatus.Information = 0;
321 status = STATUS_NOT_SUPPORTED;
323 /* irp->IoStatus.Information not freed. */
329 return driver__complete_irp(irp, irp->IoStatus.Information, status);
333 GUID_BUS_TYPE_INTERNAL,
347 static NTSTATUS STDCALL WvBusPnpQueryBusInfo_(IN WV_SP_BUS_T bus, IN PIRP irp) {
348 PPNP_BUS_INFORMATION pnp_bus_info;
351 pnp_bus_info = wv_palloc(sizeof *pnp_bus_info);
352 if (pnp_bus_info == NULL) {
353 DBG("wv_palloc IRP_MN_QUERY_BUS_INFORMATION\n");
354 status = STATUS_INSUFFICIENT_RESOURCES;
355 goto alloc_pnp_bus_info;
357 pnp_bus_info->BusTypeGuid = GUID_BUS_TYPE_INTERNAL;
358 pnp_bus_info->LegacyBusType = PNPBus;
359 pnp_bus_info->BusNumber = 0;
360 irp->IoStatus.Information = (ULONG_PTR) pnp_bus_info;
361 status = STATUS_SUCCESS;
363 /* irp-IoStatus.Information (pnp_bus_info) not freed. */
366 irp->IoStatus.Status = status;
367 IoCompleteRequest(irp, IO_NO_INCREMENT);
371 static NTSTATUS STDCALL WvBusPnpSimple_(
377 WV_SP_DEV_T dev = &bus->Dev;
378 PDEVICE_OBJECT lower = bus->LowerDeviceObject;
381 case IRP_MN_QUERY_PNP_DEVICE_STATE:
382 DBG("bus_pnp: IRP_MN_QUERY_PNP_DEVICE_STATE\n");
383 irp->IoStatus.Information = 0;
384 status = STATUS_SUCCESS;
387 case IRP_MN_QUERY_STOP_DEVICE:
388 DBG("bus_pnp: IRP_MN_QUERY_STOP_DEVICE\n");
389 dev->OldState = dev->State;
390 dev->State = WvDevStateStopPending;
391 status = STATUS_SUCCESS;
394 case IRP_MN_CANCEL_STOP_DEVICE:
395 DBG("bus_pnp: IRP_MN_CANCEL_STOP_DEVICE\n");
396 dev->State = dev->OldState;
397 status = STATUS_SUCCESS;
400 case IRP_MN_STOP_DEVICE:
401 DBG("bus_pnp: IRP_MN_STOP_DEVICE\n");
402 dev->OldState = dev->State;
403 dev->State = WvDevStateStopped;
404 status = STATUS_SUCCESS;
407 case IRP_MN_QUERY_REMOVE_DEVICE:
408 DBG("bus_pnp: IRP_MN_QUERY_REMOVE_DEVICE\n");
409 dev->OldState = dev->State;
410 dev->State = WvDevStateRemovePending;
411 status = STATUS_SUCCESS;
414 case IRP_MN_CANCEL_REMOVE_DEVICE:
415 DBG("bus_pnp: IRP_MN_CANCEL_REMOVE_DEVICE\n");
416 dev->State = dev->OldState;
417 status = STATUS_SUCCESS;
420 case IRP_MN_SURPRISE_REMOVAL:
421 DBG("bus_pnp: IRP_MN_SURPRISE_REMOVAL\n");
422 dev->OldState = dev->State;
423 dev->State = WvDevStateSurpriseRemovePending;
424 status = STATUS_SUCCESS;
427 case IRP_MN_QUERY_RESOURCES:
428 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
429 DBG("bus_pnp: IRP_MN_QUERY_RESOURCE*\n");
430 IoCompleteRequest(irp, IO_NO_INCREMENT);
431 return STATUS_SUCCESS;
434 DBG("bus_pnp: Unhandled IRP_MN_*: %d\n", code);
435 status = irp->IoStatus.Status;
438 irp->IoStatus.Status = status;
440 IoSkipCurrentIrpStackLocation(irp);
441 return IoCallDriver(lower, irp);
443 return driver__complete_irp(irp, irp->IoStatus.Information, status);
446 /* Bus PnP dispatch routine. */
447 winvblock__lib_func NTSTATUS STDCALL WvBusPnp(
452 WV_SP_DEV_T dev = &bus->Dev;
455 case IRP_MN_QUERY_ID:
456 DBG("bus_pnp: IRP_MN_QUERY_ID\n");
457 return WvDevPnpQueryId(dev, irp);
459 case IRP_MN_QUERY_DEVICE_TEXT:
460 DBG("bus_pnp: IRP_MN_QUERY_DEVICE_TEXT\n");
461 return WvBusPnpQueryDevText_(bus, irp);
463 case IRP_MN_QUERY_BUS_INFORMATION:
464 DBG("bus_pnp: IRP_MN_QUERY_BUS_INFORMATION\n");
465 return WvBusPnpQueryBusInfo_(bus, irp);
467 case IRP_MN_QUERY_DEVICE_RELATIONS:
468 DBG("bus_pnp: IRP_MN_QUERY_DEVICE_RELATIONS\n");
469 return WvBusPnpQueryDevRelations_(bus, irp);
471 case IRP_MN_QUERY_CAPABILITIES:
472 DBG("bus_pnp: IRP_MN_QUERY_CAPABILITIES\n");
473 return WvBusPnpQueryCapabilities_(bus, irp);
475 case IRP_MN_REMOVE_DEVICE:
476 DBG("bus_pnp: IRP_MN_REMOVE_DEVICE\n");
477 return WvBusPnpRemoveDev_(bus, irp);
479 case IRP_MN_START_DEVICE:
480 DBG("bus_pnp: IRP_MN_START_DEVICE\n");
481 return WvBusPnpStartDev_(bus, irp);
484 return WvBusPnpSimple_(bus, irp, code);