VirtualBox

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

Last change on this file since 63206 was 62853, checked in by vboxsync, 8 years ago

GAs/common: warnings

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

© 2023 Oracle
ContactPrivacy policyTerms of Use