VirtualBox

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

Last change on this file since 44986 was 44986, checked in by vboxsync, 12 years ago

VBoxGuest-win-pnp.cpp: More cleaning up.

  • 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 44986 2013-03-11 13:49:43Z vboxsync $ */
2/** @file
3 * VBoxGuest-win-pnp - Windows Plug'n'Play specifics.
4 */
5
6/*
7 * Copyright (C) 2010-2013 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* Header Files *
20*******************************************************************************/
21#include "VBoxGuest-win.h"
22#include "VBoxGuestInternal.h"
23#include <VBox/err.h>
24#include <VBox/log.h>
25#include <VBox/version.h>
26#include <VBox/VBoxGuestLib.h>
27
28
29/*******************************************************************************
30* Defined Constants And Macros *
31*******************************************************************************/
32RT_C_DECLS_BEGIN
33static NTSTATUS vbgdNtSendIrpSynchronously(PDEVICE_OBJECT pDevObj, PIRP pIrp, BOOLEAN fStrict);
34static NTSTATUS vbgdNtPnPIrpComplete(PDEVICE_OBJECT pDevObj, PIRP pIrp, PKEVENT pEvent);
35static VOID vbgdNtShowDeviceResources(PCM_PARTIAL_RESOURCE_LIST pResourceList);
36RT_C_DECLS_END
37
38#ifdef ALLOC_PRAGMA
39# pragma alloc_text(PAGE, vbgdNtPnP)
40# pragma alloc_text(PAGE, vbgdNtPower)
41# pragma alloc_text(PAGE, vbgdNtSendIrpSynchronously)
42# pragma alloc_text(PAGE, vbgdNtShowDeviceResources)
43#endif
44
45
46/**
47 * Irp completion routine for PnP Irps we send.
48 *
49 * @param pDevObj Device object.
50 * @param pIrp Request packet.
51 * @param event Semaphore.
52 * @return NT status code
53 */
54static NTSTATUS vbgdNtPnpIrpComplete(PDEVICE_OBJECT pDevObj, PIRP pIrp, PKEVENT pEvent)
55{
56 KeSetEvent(pEvent, 0, FALSE);
57 return STATUS_MORE_PROCESSING_REQUIRED;
58}
59
60
61/**
62 * Helper to send a PnP IRP and wait until it's done.
63 *
64 * @param pDevObj Device object.
65 * @param pIrp Request packet.
66 * @param fStrict When set, returns an error if the IRP gives an error.
67 * @return NT status code
68 */
69static NTSTATUS vbgdNtSendIrpSynchronously(PDEVICE_OBJECT pDevObj, PIRP pIrp, BOOLEAN fStrict)
70{
71 KEVENT Event;
72
73 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
74
75 IoCopyCurrentIrpStackLocationToNext(pIrp);
76 IoSetCompletionRoutine(pIrp, (PIO_COMPLETION_ROUTINE)vbgdNtPnpIrpComplete,
77 &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(("VBoxGuest::vbgdNtSendIrpSynchronously: 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 vbgdNtPnP(PDEVICE_OBJECT pDevObj, PIRP pIrp)
105{
106 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)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(("VBoxGuest::vbgdNtGuestPnp: 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(("VBoxGuest::vbgdNtVBoxGuestPnP: START_DEVICE\n"));
147
148 /* This must be handled first by the lower driver. */
149 rc = vbgdNtSendIrpSynchronously(pDevExt->win.s.pNextLowerDriver, pIrp, TRUE);
150
151 if ( NT_SUCCESS(rc)
152 && NT_SUCCESS(pIrp->IoStatus.Status))
153 {
154 Log(("VBoxGuest::vbgdNtVBoxGuestPnP: START_DEVICE: pStack->Parameters.StartDevice.AllocatedResources = %p\n",
155 pStack->Parameters.StartDevice.AllocatedResources));
156
157 if (!pStack->Parameters.StartDevice.AllocatedResources)
158 {
159 Log(("VBoxGuest::vbgdNtVBoxGuestPnP: START_DEVICE: No resources, pDevExt = %p, nextLowerDriver = %p!\n",
160 pDevExt, pDevExt ? pDevExt->win.s.pNextLowerDriver : NULL));
161 rc = STATUS_UNSUCCESSFUL;
162 }
163 else
164 {
165 rc = vbgdNtInit(pDevObj, pIrp);
166 }
167 }
168
169 if (NT_ERROR(rc))
170 {
171 Log(("VBoxGuest::vbgdNtGuestPnp: START_DEVICE: Error: rc = 0x%x\n", rc));
172
173 /* Need to unmap memory in case of errors ... */
174 vbgdNtUnmapVMMDevMemory(pDevExt);
175 }
176 break;
177 }
178
179 case IRP_MN_CANCEL_REMOVE_DEVICE:
180 {
181 Log(("VBoxGuest::vbgdNtVBoxGuestPnP: CANCEL_REMOVE_DEVICE\n"));
182
183 /* This must be handled first by the lower driver. */
184 rc = vbgdNtSendIrpSynchronously(pDevExt->win.s.pNextLowerDriver, pIrp, TRUE);
185
186 if (NT_SUCCESS(rc) && pDevExt->win.s.devState == PENDINGREMOVE)
187 {
188 /* Return to the state prior to receiving the IRP_MN_QUERY_REMOVE_DEVICE request. */
189 pDevExt->win.s.devState = pDevExt->win.s.prevDevState;
190 }
191
192 /* Complete the IRP. */
193 break;
194 }
195
196 case IRP_MN_SURPRISE_REMOVAL:
197 {
198 Log(("VBoxGuest::vbgdNtVBoxGuestPnP: IRP_MN_SURPRISE_REMOVAL\n"));
199
200 VBOXGUEST_UPDATE_DEVSTATE(pDevExt, 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->win.s.pNextLowerDriver, pIrp);
213
214 /* Do not complete the IRP. */
215 return rc;
216 }
217
218 case IRP_MN_QUERY_REMOVE_DEVICE:
219 {
220 Log(("VBoxGuest::vbgdNtVBoxGuestPnP: QUERY_REMOVE_DEVICE\n"));
221
222#ifdef VBOX_REBOOT_ON_UNINSTALL
223 Log(("VBoxGuest::vbgdNtGuestPnp: 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, 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->win.s.pNextLowerDriver, pIrp);
237 Log(("VBoxGuest::vbgdNtGuestPnp: 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(("VBoxGuest::vbgdNtVBoxGuestPnP: REMOVE_DEVICE\n"));
252
253 VBOXGUEST_UPDATE_DEVSTATE(pDevExt, REMOVED);
254
255 /* Free hardware resources. */
256 /* @todo this should actually free I/O ports, interrupts, etc. */
257 rc = vbgdNtCleanup(pDevObj);
258 Log(("VBoxGuest::vbgdNtGuestPnp: REMOVE_DEVICE: vbgdNtCleanup rc = 0x%08X\n", rc));
259
260 /*
261 * We need to send the remove down the stack before we detach,
262 * but we don't need to wait for the completion of this operation
263 * (and to register a completion routine).
264 */
265 pIrp->IoStatus.Status = STATUS_SUCCESS;
266
267 IoSkipCurrentIrpStackLocation(pIrp);
268
269 rc = IoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp);
270 Log(("VBoxGuest::vbgdNtGuestPnp: REMOVE_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
271
272 IoDetachDevice(pDevExt->win.s.pNextLowerDriver);
273
274 Log(("VBoxGuest::vbgdNtGuestPnp: REMOVE_DEVICE: Removing device ...\n"));
275
276 /* Destroy device extension and clean up everything else. */
277 VBoxGuestDeleteDevExt(pDevExt);
278
279 /* Remove DOS device + symbolic link. */
280 UNICODE_STRING win32Name;
281 RtlInitUnicodeString(&win32Name, VBOXGUEST_DEVICE_NAME_DOS);
282 IoDeleteSymbolicLink(&win32Name);
283
284 Log(("VBoxGuest::vbgdNtGuestPnp: REMOVE_DEVICE: Deleting device ...\n"));
285
286 /* Last action: Delete our device! pDevObj is *not* failed
287 * anymore after this call! */
288 IoDeleteDevice(pDevObj);
289
290 Log(("VBoxGuest::vbgdNtGuestPnp: REMOVE_DEVICE: Device removed!\n"));
291
292 /* Propagating rc from IoCallDriver. */
293 return rc; /* Make sure that we don't do anything below here anymore! */
294 }
295
296 case IRP_MN_CANCEL_STOP_DEVICE:
297 {
298 Log(("VBoxGuest::vbgdNtVBoxGuestPnP: CANCEL_STOP_DEVICE\n"));
299
300 /* This must be handled first by the lower driver. */
301 rc = vbgdNtSendIrpSynchronously(pDevExt->win.s.pNextLowerDriver, pIrp, TRUE);
302
303 if (NT_SUCCESS(rc) && pDevExt->win.s.devState == PENDINGSTOP)
304 {
305 /* Return to the state prior to receiving the IRP_MN_QUERY_STOP_DEVICE request. */
306 pDevExt->win.s.devState = pDevExt->win.s.prevDevState;
307 }
308
309 /* Complete the IRP. */
310 break;
311 }
312
313 case IRP_MN_QUERY_STOP_DEVICE:
314 {
315 Log(("VBoxGuest::vbgdNtVBoxGuestPnP: QUERY_STOP_DEVICE\n"));
316
317#ifdef VBOX_REBOOT_ON_UNINSTALL
318 Log(("VBoxGuest::vbgdNtGuestPnp: QUERY_STOP_DEVICE: Device cannot be stopped without a reboot!\n"));
319 pIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
320#endif
321
322 if (NT_SUCCESS(rc))
323 {
324 VBOXGUEST_UPDATE_DEVSTATE(pDevExt, PENDINGSTOP);
325
326 /* This IRP passed down to lower driver. */
327 pIrp->IoStatus.Status = STATUS_SUCCESS;
328
329 IoSkipCurrentIrpStackLocation(pIrp);
330
331 rc = IoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp);
332 Log(("VBoxGuest::vbgdNtGuestPnp: QUERY_STOP_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
333
334 /* we must not do anything with the IRP after doing IoSkip & CallDriver
335 * since the driver below us will complete (or already have completed) the IRP.
336 * I.e. just return the status we got from IoCallDriver */
337 return rc;
338 }
339
340 /* Complete the IRP on failure. */
341 break;
342 }
343
344 case IRP_MN_STOP_DEVICE:
345 {
346 Log(("VBoxGuest::vbgdNtVBoxGuestPnP: STOP_DEVICE\n"));
347
348 VBOXGUEST_UPDATE_DEVSTATE(pDevExt, STOPPED);
349
350 /* Free hardware resources. */
351 /* @todo this should actually free I/O ports, interrupts, etc. */
352 rc = vbgdNtCleanup(pDevObj);
353 Log(("VBoxGuest::vbgdNtGuestPnp: STOP_DEVICE: cleaning up, rc = 0x%x\n", rc));
354
355 /* Pass to the lower driver. */
356 pIrp->IoStatus.Status = STATUS_SUCCESS;
357
358 IoSkipCurrentIrpStackLocation(pIrp);
359
360 rc = IoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp);
361 Log(("VBoxGuest::vbgdNtGuestPnp: STOP_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
362
363 return rc;
364 }
365
366 default:
367 {
368 IoSkipCurrentIrpStackLocation(pIrp);
369 rc = IoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp);
370 return rc;
371 }
372 }
373
374 pIrp->IoStatus.Status = rc;
375 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
376
377 Log(("VBoxGuest::vbgdNtGuestPnp: Returning with rc = 0x%x\n", rc));
378 return rc;
379}
380
381
382/**
383 * Handle the power completion event.
384 *
385 * @returns NT status code.
386 * @param pDevObj Targetted device object.
387 * @param pIrp IO request packet.
388 * @param pContext Context value passed to IoSetCompletionRoutine in VBoxGuestPower.
389 */
390static NTSTATUS vbgdNtPowerComplete(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp, IN PVOID pContext)
391{
392 PIO_STACK_LOCATION pIrpSp;
393 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pContext;
394
395 ASSERT(pDevExt);
396 ASSERT(pDevExt->signature == DEVICE_EXTENSION_SIGNATURE);
397
398 pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
399 if (pIrpSp)
400 {
401 ASSERT(pIrpSp->MajorFunction == IRP_MJ_POWER);
402 if (NT_SUCCESS(pIrp->IoStatus.Status))
403 {
404 switch (pIrpSp->MinorFunction)
405 {
406 case IRP_MN_SET_POWER:
407
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
423 return STATUS_SUCCESS;
424}
425
426
427/**
428 * Handle the Power requests.
429 *
430 * @returns NT status code
431 * @param pDevObj device object
432 * @param pIrp IRP
433 */
434NTSTATUS vbgdNtPower(PDEVICE_OBJECT pDevObj, PIRP pIrp)
435{
436 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
437 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
438 POWER_STATE_TYPE enmPowerType = pStack->Parameters.Power.Type;
439 POWER_STATE PowerState = pStack->Parameters.Power.State;
440 POWER_ACTION enmPowerAction = pStack->Parameters.Power.ShutdownType;
441
442 Log(("VBoxGuest::vbgdNtGuestPower\n"));
443
444 switch (pStack->MinorFunction)
445 {
446 case IRP_MN_SET_POWER:
447 {
448 Log(("VBoxGuest::vbgdNtGuestPower: IRP_MN_SET_POWER, type= %d\n", enmPowerType));
449 switch (enmPowerType)
450 {
451 case SystemPowerState:
452 {
453 Log(("VBoxGuest::vbgdNtGuestPower: SystemPowerState, action = %d, state = %d/%d\n",
454 enmPowerAction, PowerState.SystemState, PowerState.DeviceState));
455
456 switch (enmPowerAction)
457 {
458 case PowerActionSleep:
459
460 /* System now is in a working state. */
461 if (PowerState.SystemState == PowerSystemWorking)
462 {
463 if ( pDevExt
464 && pDevExt->win.s.LastSystemPowerAction == PowerActionHibernate)
465 {
466 Log(("VBoxGuest::vbgdNtGuestPower: Returning from hibernation!\n"));
467 int rc = VBoxGuestReinitDevExtAfterHibernation(pDevExt,
468 vbgdNtVersionToOSType(g_enmVbgdNtVer));
469 if (RT_FAILURE(rc))
470 Log(("VBoxGuest::vbgdNtGuestPower: Cannot re-init VMMDev chain, rc = %d!\n", rc));
471 }
472 }
473 break;
474
475 case PowerActionShutdownReset:
476 {
477 Log(("VBoxGuest::vbgdNtGuestPower: Power action reset!\n"));
478
479 /* Tell the VMM that we no longer support mouse pointer integration. */
480 VMMDevReqMouseStatus *pReq = NULL;
481 int vrc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof (VMMDevReqMouseStatus),
482 VMMDevReq_SetMouseStatus);
483 if (RT_SUCCESS(vrc))
484 {
485 pReq->mouseFeatures = 0;
486 pReq->pointerXPos = 0;
487 pReq->pointerYPos = 0;
488
489 vrc = VbglGRPerform(&pReq->header);
490 if (RT_FAILURE(vrc))
491 {
492 Log(("VBoxGuest::PowerStateRequest: error communicating new power status to VMMDev. "
493 "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(("VBoxGuest::vbgdNtGuestPower: Power action shutdown!\n"));
508 if (PowerState.SystemState >= PowerSystemShutdown)
509 {
510 Log(("VBoxGuest::vbgdNtGuestPower: Telling the VMMDev to close the VM ...\n"));
511
512 VMMDevPowerStateRequest *pReq = pDevExt->win.s.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(("VBoxGuest::PowerStateRequest: 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(("VBoxGuest::vbgdNtGuestPower: 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->win.s.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 vbgdNtPowerComplete,
567 (PVOID)pDevExt,
568 TRUE,
569 TRUE,
570 TRUE);
571 return PoCallDriver(pDevExt->win.s.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