VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win-pnp.cpp@ 32877

Last change on this file since 32877 was 32457, checked in by vboxsync, 14 years ago

VBoxGuest/win: Delayed wake-up handling in DPC handler (requires RTSPINLOCK_NT_HACK_NOIRQ to be set, see r65824), additional documentation and cleanup.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.3 KB
Line 
1/** @file
2 *
3 * VBoxGuest-win-pnp - Windows Plug'n'Play specifics.
4 *
5 * Copyright (C) 2010 Oracle Corporation
6 *
7 * This file is part of VirtualBox Open Source Edition (OSE), as
8 * available from http://www.virtualbox.org. This file is free software;
9 * you can redistribute it and/or modify it under the terms of the GNU
10 * General Public License (GPL) as published by the Free Software
11 * Foundation, in version 2 as it comes in the "COPYING" file of the
12 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
13 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
14 */
15
16/*******************************************************************************
17* Header Files *
18*******************************************************************************/
19#include "VBoxGuest-win.h"
20#include "VBoxGuestInternal.h"
21#include <VBox/err.h>
22#include <VBox/log.h>
23#include <VBox/version.h>
24#include <VBox/VBoxGuestLib.h>
25
26
27/*******************************************************************************
28* Defined Constants And Macros *
29*******************************************************************************/
30extern winVersion_t g_winVersion;
31
32RT_C_DECLS_BEGIN
33static NTSTATUS vboxguestwinSendIrpSynchronously(PDEVICE_OBJECT pDevObj, PIRP pIrp, BOOLEAN fStrict);
34static NTSTATUS vboxguestwinPnPIrpComplete(PDEVICE_OBJECT pDevObj, PIRP pIrp, PKEVENT pEvent);
35static VOID vboxguestwinShowDeviceResources(PCM_PARTIAL_RESOURCE_LIST pResourceList);
36RT_C_DECLS_END
37
38#ifdef ALLOC_PRAGMA
39#pragma alloc_text (PAGE, vboxguestwinPnP)
40#pragma alloc_text (PAGE, vboxguestwinPower)
41#pragma alloc_text (PAGE, vboxguestwinSendIrpSynchronously)
42#pragma alloc_text (PAGE, vboxguestwinShowDeviceResources)
43#endif
44
45/* Reenable logging, this was #undef'ed on iprt/log.h for RING0. */
46#define LOG_ENABLED
47
48
49/*******************************************************************************
50* Internal Functions *
51*******************************************************************************/
52
53/**
54 * Irp completion routine for PnP Irps we send.
55 *
56 * @param pDevObj Device object.
57 * @param pIrp Request packet.
58 * @param event Semaphore.
59 * @return NT status code
60 */
61static NTSTATUS vboxguestwinPnpIrpComplete(PDEVICE_OBJECT pDevObj, PIRP pIrp, PKEVENT pEvent)
62{
63 KeSetEvent(pEvent, 0, FALSE);
64 return STATUS_MORE_PROCESSING_REQUIRED;
65}
66
67
68/**
69 * Helper to send a PnP IRP and wait until it's done.
70 *
71 * @param pDevObj Device object.
72 * @param pIrp Request packet.
73 * @param fStrict When set, returns an error if the IRP gives an error.
74 * @return NT status code
75 */
76static NTSTATUS vboxguestwinSendIrpSynchronously(PDEVICE_OBJECT pDevObj, PIRP pIrp, BOOLEAN fStrict)
77{
78 KEVENT event;
79
80 KeInitializeEvent(&event, SynchronizationEvent, FALSE);
81
82 IoCopyCurrentIrpStackLocationToNext(pIrp);
83 IoSetCompletionRoutine(pIrp, (PIO_COMPLETION_ROUTINE)vboxguestwinPnpIrpComplete,
84 &event, TRUE, TRUE, TRUE);
85
86 NTSTATUS rc = IoCallDriver(pDevObj, pIrp);
87
88 if (rc == STATUS_PENDING)
89 {
90 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
91 rc = pIrp->IoStatus.Status;
92 }
93
94 if (!fStrict
95 && (rc == STATUS_NOT_SUPPORTED || rc == STATUS_INVALID_DEVICE_REQUEST))
96 {
97 rc = STATUS_SUCCESS;
98 }
99
100 Log(("VBoxGuest::vboxguestwinSendIrpSynchronously: Returning 0x%x\n", rc));
101 return rc;
102}
103
104
105/**
106 * PnP Request handler.
107 *
108 * @param pDevObj Device object.
109 * @param pIrp Request packet.
110 */
111NTSTATUS vboxguestwinPnP(PDEVICE_OBJECT pDevObj, PIRP pIrp)
112{
113 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
114 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
115
116#ifdef LOG_ENABLED
117 static char* aszFnctName[] =
118 {
119 "IRP_MN_START_DEVICE",
120 "IRP_MN_QUERY_REMOVE_DEVICE",
121 "IRP_MN_REMOVE_DEVICE",
122 "IRP_MN_CANCEL_REMOVE_DEVICE",
123 "IRP_MN_STOP_DEVICE",
124 "IRP_MN_QUERY_STOP_DEVICE",
125 "IRP_MN_CANCEL_STOP_DEVICE",
126 "IRP_MN_QUERY_DEVICE_RELATIONS",
127 "IRP_MN_QUERY_INTERFACE",
128 "IRP_MN_QUERY_CAPABILITIES",
129 "IRP_MN_QUERY_RESOURCES",
130 "IRP_MN_QUERY_RESOURCE_REQUIREMENTS",
131 "IRP_MN_QUERY_DEVICE_TEXT",
132 "IRP_MN_FILTER_RESOURCE_REQUIREMENTS",
133 "",
134 "IRP_MN_READ_CONFIG",
135 "IRP_MN_WRITE_CONFIG",
136 "IRP_MN_EJECT",
137 "IRP_MN_SET_LOCK",
138 "IRP_MN_QUERY_ID",
139 "IRP_MN_QUERY_PNP_DEVICE_STATE",
140 "IRP_MN_QUERY_BUS_INFORMATION",
141 "IRP_MN_DEVICE_USAGE_NOTIFICATION",
142 "IRP_MN_SURPRISE_REMOVAL",
143 };
144 Log(("VBoxGuest::vboxguestwinGuestPnp: MinorFunction: %s\n",
145 pStack->MinorFunction < (sizeof(aszFnctName) / sizeof(aszFnctName[0]))
146 ? aszFnctName[pStack->MinorFunction]
147 : "Unknown"));
148#endif
149
150 NTSTATUS rc = STATUS_SUCCESS;
151 switch (pStack->MinorFunction)
152 {
153 case IRP_MN_START_DEVICE:
154 {
155 Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: START_DEVICE\n"));
156 rc = vboxguestwinSendIrpSynchronously(pDevExt->win.s.pNextLowerDriver, pIrp, TRUE);
157
158 if ( NT_SUCCESS(rc)
159 && NT_SUCCESS(pIrp->IoStatus.Status))
160 {
161 Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: START_DEVICE: pStack->Parameters.StartDevice.AllocatedResources = %p\n",
162 pStack->Parameters.StartDevice.AllocatedResources));
163
164 if (!pStack->Parameters.StartDevice.AllocatedResources)
165 {
166 Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: START_DEVICE: No resources, pDevExt = %p, nextLowerDriver = %p!\n",
167 pDevExt, pDevExt ? pDevExt->win.s.pNextLowerDriver : NULL));
168 rc = STATUS_UNSUCCESSFUL;
169 }
170 else
171 {
172 rc = vboxguestwinInit(pDevObj, pIrp);
173 }
174 }
175
176 if (NT_ERROR(rc))
177 {
178 Log(("VBoxGuest::vboxguestwinGuestPnp: START_DEVICE: Error: rc = 0x%x\n", rc));
179
180 /* Need to unmap memory in case of errors ... */
181 vboxguestwinUnmapVMMDevMemory(pDevExt);
182 }
183 break;
184 }
185
186 case IRP_MN_QUERY_PNP_DEVICE_STATE:
187 {
188 Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: QUERY_PNP_DEVICE_STATE\n"));
189 break;
190 }
191
192 case IRP_MN_CANCEL_REMOVE_DEVICE:
193 {
194 Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: CANCEL_REMOVE_DEVICE\n"));
195 break;
196 }
197
198 case IRP_MN_QUERY_REMOVE_DEVICE:
199 {
200 Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: QUERY_REMOVE_DEVICE\n"));
201
202#ifdef VBOX_REBOOT_ON_UNINSTALL
203 /* The device can not be removed without a reboot. */
204 if (pDevExt->win.s.devState == WORKING)
205 {
206 Log(("VBoxGuest::vboxguestwinGuestPnp: QUERY_REMOVE_DEVICE: Device cannot be removed without a reboot!\n"));
207 pDevExt->win.s.devState = PENDINGREMOVE;
208 }
209 rc = STATUS_UNSUCCESSFUL;
210 Log(("VBoxGuest::vboxguestwinGuestPnp: QUERY_REMOVE_DEVICE: Refuse with rc = %Rrc\n", rc));
211#else
212 if (pDevExt->win.s.devState == WORKING)
213 pDevExt->win.s.devState = PENDINGREMOVE;
214#endif /* VBOX_REBOOT_ON_UNINSTALL */
215 break;
216 }
217
218 case IRP_MN_REMOVE_DEVICE:
219 {
220 Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: REMOVE_DEVICE\n"));
221 if (pDevExt->win.s.devState == PENDINGREMOVE)
222 {
223 rc = vboxguestwinCleanup(pDevObj);
224 if (NT_SUCCESS(rc))
225 {
226 /*
227 * We need to send the remove down the stack before we detach,
228 * but we don't need to wait for the completion of this operation
229 * (and to register a completion routine).
230 */
231 pIrp->IoStatus.Status = STATUS_SUCCESS;
232 IoSkipCurrentIrpStackLocation(pIrp);
233
234 if (pDevExt->win.s.pNextLowerDriver != NULL)
235 {
236 rc = IoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp);
237 IoDetachDevice(pDevExt->win.s.pNextLowerDriver);
238
239 Log(("VBoxGuest::vboxguestwinGuestPnp: REMOVE_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
240 }
241
242 Log(("VBoxGuest::vboxguestwinGuestPnp: REMOVE_DEVICE: Removing device ...\n"));
243
244 /* Remove DOS device + symbolic link. */
245 UNICODE_STRING win32Name;
246 RtlInitUnicodeString(&win32Name, VBOXGUEST_DEVICE_NAME_DOS);
247 IoDeleteSymbolicLink(&win32Name);
248
249 pDevExt->win.s.devState = REMOVED;
250
251 Log(("VBoxGuest::vboxguestwinGuestPnp: REMOVE_DEVICE: Deleting device ...\n"));
252
253 /* Last action: Delete our device! pDevObj is *not* failed
254 * anymore after this call! */
255 IoDeleteDevice(pDevObj);
256
257 Log(("VBoxGuest::vboxguestwinGuestPnp: REMOVE_DEVICE: Device removed!\n"));
258 return rc; /* Make sure that we don't do anything below here anymore! */
259 }
260 else
261 Log(("VBoxGuest::vboxguestwinGuestPnp: REMOVE_DEVICE: Error while cleaning up, rc = 0x%x\n", rc));
262 }
263 else
264 Log(("VBoxGuest::vboxguestwinGuestPnp: REMOVE_DEVICE: Devices state is not PENDINGREMOVE but %d\n",
265 pDevExt->win.s.devState));
266 break;
267 }
268
269 case IRP_MN_CANCEL_STOP_DEVICE:
270 {
271 Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: CANCEL_STOP_DEVICE\n"));
272 break;
273 }
274
275 case IRP_MN_QUERY_STOP_DEVICE:
276 {
277 Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: QUERY_STOP_DEVICE\n"));
278 if (pDevExt->win.s.devState == WORKING)
279 pDevExt->win.s.devState = PENDINGSTOP;
280#ifdef VBOX_REBOOT_ON_UNINSTALL
281 Log(("VBoxGuest::vboxguestwinGuestPnp: QUERY_STOP_DEVICE: Device cannot be stopped!\n"));
282
283 /* The device can not be stopped without a reboot. */
284 pIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
285 Log(("VBoxGuest::vboxguestwinGuestPnp: QUERY_STOP_DEVICE: Refuse with rc = 0x%x\n", rc));
286#endif /* VBOX_REBOOT_ON_UNINSTALL */
287 break;
288 }
289
290 case IRP_MN_STOP_DEVICE:
291 {
292 Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: STOP_DEVICE\n"));
293
294 if (pDevExt->win.s.devState == PENDINGSTOP)
295 {
296 rc = vboxguestwinCleanup(pDevObj);
297 if (NT_SUCCESS(rc))
298 {
299 pDevExt->win.s.devState = STOPPED;
300 IoInvalidateDeviceState(pDevObj);
301 Log(("VBoxGuest::vboxguestwinGuestPnp: STOP_DEVICE: Device has been disabled\n"));
302 }
303 else
304 Log(("VBoxGuest::vboxguestwinGuestPnp: STOP_DEVICE: Error while cleaning up, rc = 0x%x\n", rc));
305 }
306 else
307 Log(("VBoxGuest::vboxguestwinGuestPnp: STOP_DEVICE: Devices state is not PENDINGSTOP but %d\n",
308 pDevExt->win.s.devState));
309 break;
310 }
311
312 default:
313 {
314 IoSkipCurrentIrpStackLocation(pIrp);
315 rc = IoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp);
316 return rc;
317 }
318 }
319
320 pIrp->IoStatus.Status = rc;
321 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
322
323 Log(("VBoxGuest::vboxguestwinGuestPnp: Returning with rc = 0x%x\n", rc));
324 return rc;
325}
326
327
328/**
329 * Handle the power completion event.
330 *
331 * @returns NT status code.
332 * @param pDevObj Targetted device object.
333 * @param pIrp IO request packet.
334 * @param pContext Context value passed to IoSetCompletionRoutine in VBoxGuestPower.
335 */
336NTSTATUS vboxguestwinPowerComplete(IN PDEVICE_OBJECT pDevObj,
337 IN PIRP pIrp, IN PVOID pContext)
338{
339 PIO_STACK_LOCATION pIrpSp;
340 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pContext;
341
342 ASSERT(pDevExt);
343 ASSERT(pDevExt->signature == DEVICE_EXTENSION_SIGNATURE);
344
345 pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
346 if (pIrpSp)
347 {
348 ASSERT(pIrpSp->MajorFunction == IRP_MJ_POWER);
349 if (NT_SUCCESS(pIrp->IoStatus.Status))
350 {
351 switch (pIrpSp->MinorFunction)
352 {
353 case IRP_MN_SET_POWER:
354
355 switch (pIrpSp->Parameters.Power.Type)
356 {
357 case DevicePowerState:
358 switch (pIrpSp->Parameters.Power.State.DeviceState)
359 {
360 case PowerDeviceD0:
361 break;
362 }
363 break;
364 }
365 break;
366 }
367 }
368 }
369
370 return STATUS_SUCCESS;
371}
372
373
374/**
375 * Handle the Power requests.
376 *
377 * @returns NT status code
378 * @param pDevObj device object
379 * @param pIrp IRP
380 */
381NTSTATUS vboxguestwinPower(PDEVICE_OBJECT pDevObj, PIRP pIrp)
382{
383 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
384 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
385 POWER_STATE_TYPE powerType;
386 POWER_STATE powerState;
387 POWER_ACTION powerAction;
388
389 Log(("VBoxGuest::vboxguestwinGuestPower\n"));
390
391 powerType = pStack->Parameters.Power.Type;
392 powerAction = pStack->Parameters.Power.ShutdownType;
393 powerState = pStack->Parameters.Power.State;
394
395 switch (pStack->MinorFunction)
396 {
397 case IRP_MN_SET_POWER:
398 {
399 Log(("VBoxGuest::vboxguestwinGuestPower: IRP_MN_SET_POWER, type= %d\n", powerType));
400 switch (powerType)
401 {
402 case SystemPowerState:
403 {
404 Log(("VBoxGuest::vboxguestwinGuestPower: SystemPowerState, action = %d, state = %d\n", powerAction, powerState));
405
406 switch (powerAction)
407 {
408 case PowerActionSleep:
409
410 /* System now is in a working state. */
411 if (powerState.SystemState == PowerSystemWorking)
412 {
413 if ( pDevExt
414 && pDevExt->win.s.LastSystemPowerAction == PowerActionHibernate)
415 {
416 Log(("VBoxGuest::vboxguestwinGuestPower: Returning from hibernation!\n"));
417 int rc = VBoxGuestReinitDevExtAfterHibernation(pDevExt, vboxguestwinVersionToOSType(g_winVersion));
418 if (RT_FAILURE(rc))
419 Log(("VBoxGuest::vboxguestwinGuestPower: Cannot re-init VMMDev chain, rc = %d!\n", rc));
420 }
421 }
422 break;
423
424 case PowerActionShutdownReset:
425 {
426 Log(("VBoxGuest::vboxguestwinGuestPower: Power action reset!\n"));
427
428 /* Tell the VMM that we no longer support mouse pointer integration. */
429 VMMDevReqMouseStatus *pReq = NULL;
430 int vrc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof (VMMDevReqMouseStatus), VMMDevReq_SetMouseStatus);
431 if (RT_SUCCESS(vrc))
432 {
433 pReq->mouseFeatures = 0;
434 pReq->pointerXPos = 0;
435 pReq->pointerYPos = 0;
436
437 vrc = VbglGRPerform(&pReq->header);
438 if (RT_FAILURE(vrc))
439 {
440 Log(("VBoxGuest::PowerStateRequest: error communicating new power status to VMMDev. "
441 "vrc = %Rrc\n", vrc));
442 }
443
444 VbglGRFree(&pReq->header);
445 }
446
447 /* Don't do any cleanup here; there might be still coming in some IOCtls after we got this
448 * power action and would assert/crash when we already cleaned up all the stuff! */
449 break;
450 }
451
452 case PowerActionShutdown:
453 case PowerActionShutdownOff:
454 {
455 Log(("VBoxGuest::vboxguestwinGuestPower: Power action shutdown!\n"));
456 if (powerState.SystemState >= PowerSystemShutdown)
457 {
458 Log(("VBoxGuest::vboxguestwinGuestPower: Telling the VMMDev to close the VM ...\n"));
459
460 VMMDevPowerStateRequest *pReq = pDevExt->win.s.pPowerStateRequest;
461 int vrc = VERR_NOT_IMPLEMENTED;
462 if (pReq)
463 {
464 pReq->header.requestType = VMMDevReq_SetPowerStatus;
465 pReq->powerState = VMMDevPowerState_PowerOff;
466
467 vrc = VbglGRPerform(&pReq->header);
468 }
469 if (RT_FAILURE(vrc))
470 {
471 Log(("VBoxGuest::PowerStateRequest: Error communicating new power status to VMMDev. "
472 "vrc = %Rrc\n", vrc));
473 }
474
475 /* No need to do cleanup here; at this point we should've been
476 * turned off by VMMDev already! */
477 }
478 break;
479 }
480
481 case PowerActionHibernate:
482
483 Log(("VBoxGuest::vboxguestwinGuestPower: Power action hibernate!\n"));
484 break;
485 }
486
487 /*
488 * Save the current system power action for later use.
489 * This becomes handy when we return from hibernation for example.
490 */
491 if (pDevExt)
492 pDevExt->win.s.LastSystemPowerAction = powerAction;
493
494 break;
495 }
496 default:
497 break;
498 }
499 break;
500 }
501 default:
502 break;
503 }
504
505 /*
506 * Whether we are completing or relaying this power IRP,
507 * we must call PoStartNextPowerIrp.
508 */
509 PoStartNextPowerIrp(pIrp);
510
511 /*
512 * Send the IRP down the driver stack,
513 * using PoCallDriver (not IoCallDriver, as for non-power irps).
514 */
515 IoCopyCurrentIrpStackLocationToNext(pIrp);
516 IoSetCompletionRoutine(pIrp,
517 vboxguestwinPowerComplete,
518 (PVOID)pDevExt,
519 TRUE,
520 TRUE,
521 TRUE);
522 return PoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp);
523}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette