VirtualBox

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

Last change on this file since 37233 was 36060, checked in by vboxsync, 14 years ago

VBoxGuest-win: PNP cleanup: process only required PNP IRPs according to MSDN.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.6 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
157 /* This must be handled first by the lower driver. */
158 rc = vboxguestwinSendIrpSynchronously(pDevExt->win.s.pNextLowerDriver, pIrp, TRUE);
159
160 if ( NT_SUCCESS(rc)
161 && NT_SUCCESS(pIrp->IoStatus.Status))
162 {
163 Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: START_DEVICE: pStack->Parameters.StartDevice.AllocatedResources = %p\n",
164 pStack->Parameters.StartDevice.AllocatedResources));
165
166 if (!pStack->Parameters.StartDevice.AllocatedResources)
167 {
168 Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: START_DEVICE: No resources, pDevExt = %p, nextLowerDriver = %p!\n",
169 pDevExt, pDevExt ? pDevExt->win.s.pNextLowerDriver : NULL));
170 rc = STATUS_UNSUCCESSFUL;
171 }
172 else
173 {
174 rc = vboxguestwinInit(pDevObj, pIrp);
175 }
176 }
177
178 if (NT_ERROR(rc))
179 {
180 Log(("VBoxGuest::vboxguestwinGuestPnp: START_DEVICE: Error: rc = 0x%x\n", rc));
181
182 /* Need to unmap memory in case of errors ... */
183 vboxguestwinUnmapVMMDevMemory(pDevExt);
184 }
185 break;
186 }
187
188 case IRP_MN_CANCEL_REMOVE_DEVICE:
189 {
190 Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: CANCEL_REMOVE_DEVICE\n"));
191
192 /* This must be handled first by the lower driver. */
193 rc = vboxguestwinSendIrpSynchronously(pDevExt->win.s.pNextLowerDriver, pIrp, TRUE);
194
195 if (NT_SUCCESS(rc) && pDevExt->win.s.devState == PENDINGREMOVE)
196 {
197 /* Return to the state prior to receiving the IRP_MN_QUERY_REMOVE_DEVICE request. */
198 pDevExt->win.s.devState = pDevExt->win.s.prevDevState;
199 }
200
201 /* Complete the IRP. */
202 break;
203 }
204
205 case IRP_MN_SURPRISE_REMOVAL:
206 {
207 Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: IRP_MN_SURPRISE_REMOVAL\n"));
208
209 VBOXGUEST_UPDATE_DEVSTATE(pDevExt, SURPRISEREMOVED);
210
211 /* Do nothing here actually. Cleanup is done in IRP_MN_REMOVE_DEVICE.
212 * This request is not expected for VBoxGuest.
213 */
214 LogRel(("VBoxGuest: unexpected device removal\n"));
215
216 /* Pass to the lower driver. */
217 pIrp->IoStatus.Status = STATUS_SUCCESS;
218
219 IoSkipCurrentIrpStackLocation(pIrp);
220
221 rc = IoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp);
222
223 /* Do not complete the IRP. */
224 return rc;
225 }
226
227 case IRP_MN_QUERY_REMOVE_DEVICE:
228 {
229 Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: QUERY_REMOVE_DEVICE\n"));
230
231#ifdef VBOX_REBOOT_ON_UNINSTALL
232 Log(("VBoxGuest::vboxguestwinGuestPnp: QUERY_REMOVE_DEVICE: Device cannot be removed without a reboot.\n"));
233 rc = STATUS_UNSUCCESSFUL;
234#endif /* VBOX_REBOOT_ON_UNINSTALL */
235
236 if (NT_SUCCESS(rc))
237 {
238 VBOXGUEST_UPDATE_DEVSTATE(pDevExt, PENDINGREMOVE);
239
240 /* This IRP passed down to lower driver. */
241 pIrp->IoStatus.Status = STATUS_SUCCESS;
242
243 rc = vboxguestwinSendIrpSynchronously(pDevExt->win.s.pNextLowerDriver, pIrp, TRUE);
244
245 /* Do not complete the IRP. */
246 return rc;
247 }
248
249 /* Complete the IRP on failure. */
250 break;
251 }
252
253 case IRP_MN_REMOVE_DEVICE:
254 {
255 Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: REMOVE_DEVICE\n"));
256
257 VBOXGUEST_UPDATE_DEVSTATE(pDevExt, REMOVED);
258
259 /* Free hardware resources. */
260 /* @todo this should actually free I/O ports, interrupts, etc. */
261 rc = vboxguestwinCleanup(pDevObj);
262 Log(("VBoxGuest::vboxguestwinGuestPnp: REMOVE_DEVICE: vboxguestwinCleanup rc = 0x%08X\n", rc));
263
264 /*
265 * We need to send the remove down the stack before we detach,
266 * but we don't need to wait for the completion of this operation
267 * (and to register a completion routine).
268 */
269 pIrp->IoStatus.Status = STATUS_SUCCESS;
270
271 IoSkipCurrentIrpStackLocation(pIrp);
272
273 rc = IoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp);
274 Log(("VBoxGuest::vboxguestwinGuestPnp: REMOVE_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
275
276 IoDetachDevice(pDevExt->win.s.pNextLowerDriver);
277
278 Log(("VBoxGuest::vboxguestwinGuestPnp: REMOVE_DEVICE: Removing device ...\n"));
279
280 /* Destroy device extension and clean up everything else. */
281 VBoxGuestDeleteDevExt(pDevExt);
282
283 /* Remove DOS device + symbolic link. */
284 UNICODE_STRING win32Name;
285 RtlInitUnicodeString(&win32Name, VBOXGUEST_DEVICE_NAME_DOS);
286 IoDeleteSymbolicLink(&win32Name);
287
288 Log(("VBoxGuest::vboxguestwinGuestPnp: REMOVE_DEVICE: Deleting device ...\n"));
289
290 /* Last action: Delete our device! pDevObj is *not* failed
291 * anymore after this call! */
292 IoDeleteDevice(pDevObj);
293
294 Log(("VBoxGuest::vboxguestwinGuestPnp: REMOVE_DEVICE: Device removed!\n"));
295
296 /* Propagating rc from IoCallDriver. */
297 return rc; /* Make sure that we don't do anything below here anymore! */
298 }
299
300 case IRP_MN_CANCEL_STOP_DEVICE:
301 {
302 Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: CANCEL_STOP_DEVICE\n"));
303
304 /* This must be handled first by the lower driver. */
305 rc = vboxguestwinSendIrpSynchronously(pDevExt->win.s.pNextLowerDriver, pIrp, TRUE);
306
307 if (NT_SUCCESS(rc) && pDevExt->win.s.devState == PENDINGSTOP)
308 {
309 /* Return to the state prior to receiving the IRP_MN_QUERY_STOP_DEVICE request. */
310 pDevExt->win.s.devState = pDevExt->win.s.prevDevState;
311 }
312
313 /* Complete the IRP. */
314 break;
315 }
316
317 case IRP_MN_QUERY_STOP_DEVICE:
318 {
319 Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: QUERY_STOP_DEVICE\n"));
320
321#ifdef VBOX_REBOOT_ON_UNINSTALL
322 Log(("VBoxGuest::vboxguestwinGuestPnp: QUERY_STOP_DEVICE: Device cannot be stopped without a reboot!\n"));
323 pIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
324#endif /* VBOX_REBOOT_ON_UNINSTALL */
325
326 if (NT_SUCCESS(rc))
327 {
328 VBOXGUEST_UPDATE_DEVSTATE(pDevExt, PENDINGSTOP);
329
330 /* This IRP passed down to lower driver. */
331 pIrp->IoStatus.Status = STATUS_SUCCESS;
332
333 rc = vboxguestwinSendIrpSynchronously(pDevExt->win.s.pNextLowerDriver, pIrp, TRUE);
334
335 /* Do not complete the IRP. */
336 return rc;
337 }
338
339 /* Complete the IRP on failure. */
340 break;
341 }
342
343 case IRP_MN_STOP_DEVICE:
344 {
345 Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: STOP_DEVICE\n"));
346
347 VBOXGUEST_UPDATE_DEVSTATE(pDevExt, STOPPED);
348
349 /* Free hardware resources. */
350 /* @todo this should actually free I/O ports, interrupts, etc. */
351 rc = vboxguestwinCleanup(pDevObj);
352 Log(("VBoxGuest::vboxguestwinGuestPnp: STOP_DEVICE: cleaning up, rc = 0x%x\n", rc));
353
354 /* Pass to the lower driver. */
355 pIrp->IoStatus.Status = STATUS_SUCCESS;
356
357 IoSkipCurrentIrpStackLocation(pIrp);
358
359 rc = IoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp);
360 Log(("VBoxGuest::vboxguestwinGuestPnp: STOP_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
361
362 return rc;
363 }
364
365 default:
366 {
367 IoSkipCurrentIrpStackLocation(pIrp);
368 rc = IoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp);
369 return rc;
370 }
371 }
372
373 pIrp->IoStatus.Status = rc;
374 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
375
376 Log(("VBoxGuest::vboxguestwinGuestPnp: Returning with rc = 0x%x\n", rc));
377 return rc;
378}
379
380
381/**
382 * Handle the power completion event.
383 *
384 * @returns NT status code.
385 * @param pDevObj Targetted device object.
386 * @param pIrp IO request packet.
387 * @param pContext Context value passed to IoSetCompletionRoutine in VBoxGuestPower.
388 */
389NTSTATUS vboxguestwinPowerComplete(IN PDEVICE_OBJECT pDevObj,
390 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 vboxguestwinPower(PDEVICE_OBJECT pDevObj, PIRP pIrp)
435{
436 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
437 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
438 POWER_STATE_TYPE powerType;
439 POWER_STATE powerState;
440 POWER_ACTION powerAction;
441
442 Log(("VBoxGuest::vboxguestwinGuestPower\n"));
443
444 powerType = pStack->Parameters.Power.Type;
445 powerAction = pStack->Parameters.Power.ShutdownType;
446 powerState = pStack->Parameters.Power.State;
447
448 switch (pStack->MinorFunction)
449 {
450 case IRP_MN_SET_POWER:
451 {
452 Log(("VBoxGuest::vboxguestwinGuestPower: IRP_MN_SET_POWER, type= %d\n", powerType));
453 switch (powerType)
454 {
455 case SystemPowerState:
456 {
457 Log(("VBoxGuest::vboxguestwinGuestPower: SystemPowerState, action = %d, state = %d\n", powerAction, powerState));
458
459 switch (powerAction)
460 {
461 case PowerActionSleep:
462
463 /* System now is in a working state. */
464 if (powerState.SystemState == PowerSystemWorking)
465 {
466 if ( pDevExt
467 && pDevExt->win.s.LastSystemPowerAction == PowerActionHibernate)
468 {
469 Log(("VBoxGuest::vboxguestwinGuestPower: Returning from hibernation!\n"));
470 int rc = VBoxGuestReinitDevExtAfterHibernation(pDevExt, vboxguestwinVersionToOSType(g_winVersion));
471 if (RT_FAILURE(rc))
472 Log(("VBoxGuest::vboxguestwinGuestPower: Cannot re-init VMMDev chain, rc = %d!\n", rc));
473 }
474 }
475 break;
476
477 case PowerActionShutdownReset:
478 {
479 Log(("VBoxGuest::vboxguestwinGuestPower: Power action reset!\n"));
480
481 /* Tell the VMM that we no longer support mouse pointer integration. */
482 VMMDevReqMouseStatus *pReq = NULL;
483 int vrc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof (VMMDevReqMouseStatus), 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(("VBoxGuest::PowerStateRequest: error communicating new power status to VMMDev. "
494 "vrc = %Rrc\n", vrc));
495 }
496
497 VbglGRFree(&pReq->header);
498 }
499
500 /* Don't do any cleanup here; there might be still coming in some IOCtls after we got this
501 * power action and would assert/crash when we already cleaned up all the stuff! */
502 break;
503 }
504
505 case PowerActionShutdown:
506 case PowerActionShutdownOff:
507 {
508 Log(("VBoxGuest::vboxguestwinGuestPower: Power action shutdown!\n"));
509 if (powerState.SystemState >= PowerSystemShutdown)
510 {
511 Log(("VBoxGuest::vboxguestwinGuestPower: Telling the VMMDev to close the VM ...\n"));
512
513 VMMDevPowerStateRequest *pReq = pDevExt->win.s.pPowerStateRequest;
514 int vrc = VERR_NOT_IMPLEMENTED;
515 if (pReq)
516 {
517 pReq->header.requestType = VMMDevReq_SetPowerStatus;
518 pReq->powerState = VMMDevPowerState_PowerOff;
519
520 vrc = VbglGRPerform(&pReq->header);
521 }
522 if (RT_FAILURE(vrc))
523 {
524 Log(("VBoxGuest::PowerStateRequest: Error communicating new power status to VMMDev. "
525 "vrc = %Rrc\n", vrc));
526 }
527
528 /* No need to do cleanup here; at this point we should've been
529 * turned off by VMMDev already! */
530 }
531 break;
532 }
533
534 case PowerActionHibernate:
535
536 Log(("VBoxGuest::vboxguestwinGuestPower: Power action hibernate!\n"));
537 break;
538 }
539
540 /*
541 * Save the current system power action for later use.
542 * This becomes handy when we return from hibernation for example.
543 */
544 if (pDevExt)
545 pDevExt->win.s.LastSystemPowerAction = powerAction;
546
547 break;
548 }
549 default:
550 break;
551 }
552 break;
553 }
554 default:
555 break;
556 }
557
558 /*
559 * Whether we are completing or relaying this power IRP,
560 * we must call PoStartNextPowerIrp.
561 */
562 PoStartNextPowerIrp(pIrp);
563
564 /*
565 * Send the IRP down the driver stack,
566 * using PoCallDriver (not IoCallDriver, as for non-power irps).
567 */
568 IoCopyCurrentIrpStackLocationToNext(pIrp);
569 IoSetCompletionRoutine(pIrp,
570 vboxguestwinPowerComplete,
571 (PVOID)pDevExt,
572 TRUE,
573 TRUE,
574 TRUE);
575 return PoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp);
576}
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