VirtualBox

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

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

(C) 2016

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