VirtualBox

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

Last change on this file since 69206 was 68688, checked in by vboxsync, 7 years ago

VBoxGuest*.h,VMMDev*.h: use assertcompile.h instead of assert.h.

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