VirtualBox

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

Last change on this file since 41683 was 37423, checked in by vboxsync, 14 years ago

Ran the source code massager (scm).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.3 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 IoSkipCurrentIrpStackLocation(pIrp);
244
245 rc = IoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp);
246 Log(("VBoxGuest::vboxguestwinGuestPnp: QUERY_REMOVE_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
247
248 /* we must not do anything the IRP after doing IoSkip & CallDriver
249 * since the driver below us will complete (or already have completed) the IRP.
250 * I.e. just return the status we got from IoCallDriver */
251 return rc;
252 }
253
254 /* Complete the IRP on failure. */
255 break;
256 }
257
258 case IRP_MN_REMOVE_DEVICE:
259 {
260 Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: REMOVE_DEVICE\n"));
261
262 VBOXGUEST_UPDATE_DEVSTATE(pDevExt, REMOVED);
263
264 /* Free hardware resources. */
265 /* @todo this should actually free I/O ports, interrupts, etc. */
266 rc = vboxguestwinCleanup(pDevObj);
267 Log(("VBoxGuest::vboxguestwinGuestPnp: REMOVE_DEVICE: vboxguestwinCleanup rc = 0x%08X\n", rc));
268
269 /*
270 * We need to send the remove down the stack before we detach,
271 * but we don't need to wait for the completion of this operation
272 * (and to register a completion routine).
273 */
274 pIrp->IoStatus.Status = STATUS_SUCCESS;
275
276 IoSkipCurrentIrpStackLocation(pIrp);
277
278 rc = IoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp);
279 Log(("VBoxGuest::vboxguestwinGuestPnp: REMOVE_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
280
281 IoDetachDevice(pDevExt->win.s.pNextLowerDriver);
282
283 Log(("VBoxGuest::vboxguestwinGuestPnp: REMOVE_DEVICE: Removing device ...\n"));
284
285 /* Destroy device extension and clean up everything else. */
286 VBoxGuestDeleteDevExt(pDevExt);
287
288 /* Remove DOS device + symbolic link. */
289 UNICODE_STRING win32Name;
290 RtlInitUnicodeString(&win32Name, VBOXGUEST_DEVICE_NAME_DOS);
291 IoDeleteSymbolicLink(&win32Name);
292
293 Log(("VBoxGuest::vboxguestwinGuestPnp: REMOVE_DEVICE: Deleting device ...\n"));
294
295 /* Last action: Delete our device! pDevObj is *not* failed
296 * anymore after this call! */
297 IoDeleteDevice(pDevObj);
298
299 Log(("VBoxGuest::vboxguestwinGuestPnp: REMOVE_DEVICE: Device removed!\n"));
300
301 /* Propagating rc from IoCallDriver. */
302 return rc; /* Make sure that we don't do anything below here anymore! */
303 }
304
305 case IRP_MN_CANCEL_STOP_DEVICE:
306 {
307 Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: CANCEL_STOP_DEVICE\n"));
308
309 /* This must be handled first by the lower driver. */
310 rc = vboxguestwinSendIrpSynchronously(pDevExt->win.s.pNextLowerDriver, pIrp, TRUE);
311
312 if (NT_SUCCESS(rc) && pDevExt->win.s.devState == PENDINGSTOP)
313 {
314 /* Return to the state prior to receiving the IRP_MN_QUERY_STOP_DEVICE request. */
315 pDevExt->win.s.devState = pDevExt->win.s.prevDevState;
316 }
317
318 /* Complete the IRP. */
319 break;
320 }
321
322 case IRP_MN_QUERY_STOP_DEVICE:
323 {
324 Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: QUERY_STOP_DEVICE\n"));
325
326#ifdef VBOX_REBOOT_ON_UNINSTALL
327 Log(("VBoxGuest::vboxguestwinGuestPnp: QUERY_STOP_DEVICE: Device cannot be stopped without a reboot!\n"));
328 pIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
329#endif /* VBOX_REBOOT_ON_UNINSTALL */
330
331 if (NT_SUCCESS(rc))
332 {
333 VBOXGUEST_UPDATE_DEVSTATE(pDevExt, PENDINGSTOP);
334
335 /* This IRP passed down to lower driver. */
336 pIrp->IoStatus.Status = STATUS_SUCCESS;
337
338 IoSkipCurrentIrpStackLocation(pIrp);
339
340 rc = IoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp);
341 Log(("VBoxGuest::vboxguestwinGuestPnp: QUERY_STOP_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
342
343 /* we must not do anything with the IRP after doing IoSkip & CallDriver
344 * since the driver below us will complete (or already have completed) the IRP.
345 * I.e. just return the status we got from IoCallDriver */
346 return rc;
347 }
348
349 /* Complete the IRP on failure. */
350 break;
351 }
352
353 case IRP_MN_STOP_DEVICE:
354 {
355 Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: STOP_DEVICE\n"));
356
357 VBOXGUEST_UPDATE_DEVSTATE(pDevExt, STOPPED);
358
359 /* Free hardware resources. */
360 /* @todo this should actually free I/O ports, interrupts, etc. */
361 rc = vboxguestwinCleanup(pDevObj);
362 Log(("VBoxGuest::vboxguestwinGuestPnp: STOP_DEVICE: cleaning up, rc = 0x%x\n", rc));
363
364 /* Pass to the lower driver. */
365 pIrp->IoStatus.Status = STATUS_SUCCESS;
366
367 IoSkipCurrentIrpStackLocation(pIrp);
368
369 rc = IoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp);
370 Log(("VBoxGuest::vboxguestwinGuestPnp: STOP_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
371
372 return rc;
373 }
374
375 default:
376 {
377 IoSkipCurrentIrpStackLocation(pIrp);
378 rc = IoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp);
379 return rc;
380 }
381 }
382
383 pIrp->IoStatus.Status = rc;
384 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
385
386 Log(("VBoxGuest::vboxguestwinGuestPnp: Returning with rc = 0x%x\n", rc));
387 return rc;
388}
389
390
391/**
392 * Handle the power completion event.
393 *
394 * @returns NT status code.
395 * @param pDevObj Targetted device object.
396 * @param pIrp IO request packet.
397 * @param pContext Context value passed to IoSetCompletionRoutine in VBoxGuestPower.
398 */
399NTSTATUS vboxguestwinPowerComplete(IN PDEVICE_OBJECT pDevObj,
400 IN PIRP pIrp, IN PVOID pContext)
401{
402 PIO_STACK_LOCATION pIrpSp;
403 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pContext;
404
405 ASSERT(pDevExt);
406 ASSERT(pDevExt->signature == DEVICE_EXTENSION_SIGNATURE);
407
408 pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
409 if (pIrpSp)
410 {
411 ASSERT(pIrpSp->MajorFunction == IRP_MJ_POWER);
412 if (NT_SUCCESS(pIrp->IoStatus.Status))
413 {
414 switch (pIrpSp->MinorFunction)
415 {
416 case IRP_MN_SET_POWER:
417
418 switch (pIrpSp->Parameters.Power.Type)
419 {
420 case DevicePowerState:
421 switch (pIrpSp->Parameters.Power.State.DeviceState)
422 {
423 case PowerDeviceD0:
424 break;
425 }
426 break;
427 }
428 break;
429 }
430 }
431 }
432
433 return STATUS_SUCCESS;
434}
435
436
437/**
438 * Handle the Power requests.
439 *
440 * @returns NT status code
441 * @param pDevObj device object
442 * @param pIrp IRP
443 */
444NTSTATUS vboxguestwinPower(PDEVICE_OBJECT pDevObj, PIRP pIrp)
445{
446 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
447 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
448 POWER_STATE_TYPE powerType;
449 POWER_STATE powerState;
450 POWER_ACTION powerAction;
451
452 Log(("VBoxGuest::vboxguestwinGuestPower\n"));
453
454 powerType = pStack->Parameters.Power.Type;
455 powerAction = pStack->Parameters.Power.ShutdownType;
456 powerState = pStack->Parameters.Power.State;
457
458 switch (pStack->MinorFunction)
459 {
460 case IRP_MN_SET_POWER:
461 {
462 Log(("VBoxGuest::vboxguestwinGuestPower: IRP_MN_SET_POWER, type= %d\n", powerType));
463 switch (powerType)
464 {
465 case SystemPowerState:
466 {
467 Log(("VBoxGuest::vboxguestwinGuestPower: SystemPowerState, action = %d, state = %d\n", powerAction, powerState));
468
469 switch (powerAction)
470 {
471 case PowerActionSleep:
472
473 /* System now is in a working state. */
474 if (powerState.SystemState == PowerSystemWorking)
475 {
476 if ( pDevExt
477 && pDevExt->win.s.LastSystemPowerAction == PowerActionHibernate)
478 {
479 Log(("VBoxGuest::vboxguestwinGuestPower: Returning from hibernation!\n"));
480 int rc = VBoxGuestReinitDevExtAfterHibernation(pDevExt, vboxguestwinVersionToOSType(g_winVersion));
481 if (RT_FAILURE(rc))
482 Log(("VBoxGuest::vboxguestwinGuestPower: Cannot re-init VMMDev chain, rc = %d!\n", rc));
483 }
484 }
485 break;
486
487 case PowerActionShutdownReset:
488 {
489 Log(("VBoxGuest::vboxguestwinGuestPower: Power action reset!\n"));
490
491 /* Tell the VMM that we no longer support mouse pointer integration. */
492 VMMDevReqMouseStatus *pReq = NULL;
493 int vrc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof (VMMDevReqMouseStatus), VMMDevReq_SetMouseStatus);
494 if (RT_SUCCESS(vrc))
495 {
496 pReq->mouseFeatures = 0;
497 pReq->pointerXPos = 0;
498 pReq->pointerYPos = 0;
499
500 vrc = VbglGRPerform(&pReq->header);
501 if (RT_FAILURE(vrc))
502 {
503 Log(("VBoxGuest::PowerStateRequest: error communicating new power status to VMMDev. "
504 "vrc = %Rrc\n", vrc));
505 }
506
507 VbglGRFree(&pReq->header);
508 }
509
510 /* Don't do any cleanup here; there might be still coming in some IOCtls after we got this
511 * power action and would assert/crash when we already cleaned up all the stuff! */
512 break;
513 }
514
515 case PowerActionShutdown:
516 case PowerActionShutdownOff:
517 {
518 Log(("VBoxGuest::vboxguestwinGuestPower: Power action shutdown!\n"));
519 if (powerState.SystemState >= PowerSystemShutdown)
520 {
521 Log(("VBoxGuest::vboxguestwinGuestPower: Telling the VMMDev to close the VM ...\n"));
522
523 VMMDevPowerStateRequest *pReq = pDevExt->win.s.pPowerStateRequest;
524 int vrc = VERR_NOT_IMPLEMENTED;
525 if (pReq)
526 {
527 pReq->header.requestType = VMMDevReq_SetPowerStatus;
528 pReq->powerState = VMMDevPowerState_PowerOff;
529
530 vrc = VbglGRPerform(&pReq->header);
531 }
532 if (RT_FAILURE(vrc))
533 {
534 Log(("VBoxGuest::PowerStateRequest: Error communicating new power status to VMMDev. "
535 "vrc = %Rrc\n", vrc));
536 }
537
538 /* No need to do cleanup here; at this point we should've been
539 * turned off by VMMDev already! */
540 }
541 break;
542 }
543
544 case PowerActionHibernate:
545
546 Log(("VBoxGuest::vboxguestwinGuestPower: Power action hibernate!\n"));
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->win.s.LastSystemPowerAction = powerAction;
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,
576 * using PoCallDriver (not IoCallDriver, as for non-power irps).
577 */
578 IoCopyCurrentIrpStackLocationToNext(pIrp);
579 IoSetCompletionRoutine(pIrp,
580 vboxguestwinPowerComplete,
581 (PVOID)pDevExt,
582 TRUE,
583 TRUE,
584 TRUE);
585 return PoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp);
586}
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