VirtualBox

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

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

Don't make vbgdNtIOCtl pageable.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.7 KB
Line 
1/* $Id: VBoxGuest-win-pnp.cpp 44985 2013-03-11 13:38:24Z 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* aszFnctName[] =
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 "",
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 < (sizeof(aszFnctName) / sizeof(aszFnctName[0]))
139 ? aszFnctName[pStack->MinorFunction]
140 : "Unknown"));
141#endif
142
143 NTSTATUS rc = STATUS_SUCCESS;
144 switch (pStack->MinorFunction)
145 {
146 case IRP_MN_START_DEVICE:
147 {
148 Log(("VBoxGuest::vbgdNtVBoxGuestPnP: START_DEVICE\n"));
149
150 /* This must be handled first by the lower driver. */
151 rc = vbgdNtSendIrpSynchronously(pDevExt->win.s.pNextLowerDriver, pIrp, TRUE);
152
153 if ( NT_SUCCESS(rc)
154 && NT_SUCCESS(pIrp->IoStatus.Status))
155 {
156 Log(("VBoxGuest::vbgdNtVBoxGuestPnP: START_DEVICE: pStack->Parameters.StartDevice.AllocatedResources = %p\n",
157 pStack->Parameters.StartDevice.AllocatedResources));
158
159 if (!pStack->Parameters.StartDevice.AllocatedResources)
160 {
161 Log(("VBoxGuest::vbgdNtVBoxGuestPnP: START_DEVICE: No resources, pDevExt = %p, nextLowerDriver = %p!\n",
162 pDevExt, pDevExt ? pDevExt->win.s.pNextLowerDriver : NULL));
163 rc = STATUS_UNSUCCESSFUL;
164 }
165 else
166 {
167 rc = vbgdNtInit(pDevObj, pIrp);
168 }
169 }
170
171 if (NT_ERROR(rc))
172 {
173 Log(("VBoxGuest::vbgdNtGuestPnp: START_DEVICE: Error: rc = 0x%x\n", rc));
174
175 /* Need to unmap memory in case of errors ... */
176 vbgdNtUnmapVMMDevMemory(pDevExt);
177 }
178 break;
179 }
180
181 case IRP_MN_CANCEL_REMOVE_DEVICE:
182 {
183 Log(("VBoxGuest::vbgdNtVBoxGuestPnP: CANCEL_REMOVE_DEVICE\n"));
184
185 /* This must be handled first by the lower driver. */
186 rc = vbgdNtSendIrpSynchronously(pDevExt->win.s.pNextLowerDriver, pIrp, TRUE);
187
188 if (NT_SUCCESS(rc) && pDevExt->win.s.devState == PENDINGREMOVE)
189 {
190 /* Return to the state prior to receiving the IRP_MN_QUERY_REMOVE_DEVICE request. */
191 pDevExt->win.s.devState = pDevExt->win.s.prevDevState;
192 }
193
194 /* Complete the IRP. */
195 break;
196 }
197
198 case IRP_MN_SURPRISE_REMOVAL:
199 {
200 Log(("VBoxGuest::vbgdNtVBoxGuestPnP: IRP_MN_SURPRISE_REMOVAL\n"));
201
202 VBOXGUEST_UPDATE_DEVSTATE(pDevExt, SURPRISEREMOVED);
203
204 /* Do nothing here actually. Cleanup is done in IRP_MN_REMOVE_DEVICE.
205 * This request is not expected for VBoxGuest.
206 */
207 LogRel(("VBoxGuest: unexpected device removal\n"));
208
209 /* Pass to the lower driver. */
210 pIrp->IoStatus.Status = STATUS_SUCCESS;
211
212 IoSkipCurrentIrpStackLocation(pIrp);
213
214 rc = IoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp);
215
216 /* Do not complete the IRP. */
217 return rc;
218 }
219
220 case IRP_MN_QUERY_REMOVE_DEVICE:
221 {
222 Log(("VBoxGuest::vbgdNtVBoxGuestPnP: QUERY_REMOVE_DEVICE\n"));
223
224#ifdef VBOX_REBOOT_ON_UNINSTALL
225 Log(("VBoxGuest::vbgdNtGuestPnp: QUERY_REMOVE_DEVICE: Device cannot be removed without a reboot.\n"));
226 rc = STATUS_UNSUCCESSFUL;
227#endif /* VBOX_REBOOT_ON_UNINSTALL */
228
229 if (NT_SUCCESS(rc))
230 {
231 VBOXGUEST_UPDATE_DEVSTATE(pDevExt, PENDINGREMOVE);
232
233 /* This IRP passed down to lower driver. */
234 pIrp->IoStatus.Status = STATUS_SUCCESS;
235
236 IoSkipCurrentIrpStackLocation(pIrp);
237
238 rc = IoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp);
239 Log(("VBoxGuest::vbgdNtGuestPnp: QUERY_REMOVE_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
240
241 /* we must not do anything the IRP after doing IoSkip & CallDriver
242 * since the driver below us will complete (or already have completed) the IRP.
243 * I.e. just return the status we got from IoCallDriver */
244 return rc;
245 }
246
247 /* Complete the IRP on failure. */
248 break;
249 }
250
251 case IRP_MN_REMOVE_DEVICE:
252 {
253 Log(("VBoxGuest::vbgdNtVBoxGuestPnP: REMOVE_DEVICE\n"));
254
255 VBOXGUEST_UPDATE_DEVSTATE(pDevExt, REMOVED);
256
257 /* Free hardware resources. */
258 /* @todo this should actually free I/O ports, interrupts, etc. */
259 rc = vbgdNtCleanup(pDevObj);
260 Log(("VBoxGuest::vbgdNtGuestPnp: REMOVE_DEVICE: vbgdNtCleanup 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->win.s.pNextLowerDriver, pIrp);
272 Log(("VBoxGuest::vbgdNtGuestPnp: REMOVE_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
273
274 IoDetachDevice(pDevExt->win.s.pNextLowerDriver);
275
276 Log(("VBoxGuest::vbgdNtGuestPnp: REMOVE_DEVICE: Removing device ...\n"));
277
278 /* Destroy device extension and clean up everything else. */
279 VBoxGuestDeleteDevExt(pDevExt);
280
281 /* Remove DOS device + symbolic link. */
282 UNICODE_STRING win32Name;
283 RtlInitUnicodeString(&win32Name, VBOXGUEST_DEVICE_NAME_DOS);
284 IoDeleteSymbolicLink(&win32Name);
285
286 Log(("VBoxGuest::vbgdNtGuestPnp: 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(("VBoxGuest::vbgdNtGuestPnp: 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(("VBoxGuest::vbgdNtVBoxGuestPnP: CANCEL_STOP_DEVICE\n"));
301
302 /* This must be handled first by the lower driver. */
303 rc = vbgdNtSendIrpSynchronously(pDevExt->win.s.pNextLowerDriver, pIrp, TRUE);
304
305 if (NT_SUCCESS(rc) && pDevExt->win.s.devState == PENDINGSTOP)
306 {
307 /* Return to the state prior to receiving the IRP_MN_QUERY_STOP_DEVICE request. */
308 pDevExt->win.s.devState = pDevExt->win.s.prevDevState;
309 }
310
311 /* Complete the IRP. */
312 break;
313 }
314
315 case IRP_MN_QUERY_STOP_DEVICE:
316 {
317 Log(("VBoxGuest::vbgdNtVBoxGuestPnP: QUERY_STOP_DEVICE\n"));
318
319#ifdef VBOX_REBOOT_ON_UNINSTALL
320 Log(("VBoxGuest::vbgdNtGuestPnp: QUERY_STOP_DEVICE: Device cannot be stopped without a reboot!\n"));
321 pIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
322#endif /* VBOX_REBOOT_ON_UNINSTALL */
323
324 if (NT_SUCCESS(rc))
325 {
326 VBOXGUEST_UPDATE_DEVSTATE(pDevExt, 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->win.s.pNextLowerDriver, pIrp);
334 Log(("VBoxGuest::vbgdNtGuestPnp: 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(("VBoxGuest::vbgdNtVBoxGuestPnP: STOP_DEVICE\n"));
349
350 VBOXGUEST_UPDATE_DEVSTATE(pDevExt, STOPPED);
351
352 /* Free hardware resources. */
353 /* @todo this should actually free I/O ports, interrupts, etc. */
354 rc = vbgdNtCleanup(pDevObj);
355 Log(("VBoxGuest::vbgdNtGuestPnp: 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->win.s.pNextLowerDriver, pIrp);
363 Log(("VBoxGuest::vbgdNtGuestPnp: 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->win.s.pNextLowerDriver, pIrp);
372 return rc;
373 }
374 }
375
376 pIrp->IoStatus.Status = rc;
377 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
378
379 Log(("VBoxGuest::vbgdNtGuestPnp: 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 vbgdNtPowerComplete(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp, IN PVOID pContext)
393{
394 PIO_STACK_LOCATION pIrpSp;
395 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pContext;
396
397 ASSERT(pDevExt);
398 ASSERT(pDevExt->signature == DEVICE_EXTENSION_SIGNATURE);
399
400 pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
401 if (pIrpSp)
402 {
403 ASSERT(pIrpSp->MajorFunction == IRP_MJ_POWER);
404 if (NT_SUCCESS(pIrp->IoStatus.Status))
405 {
406 switch (pIrpSp->MinorFunction)
407 {
408 case IRP_MN_SET_POWER:
409
410 switch (pIrpSp->Parameters.Power.Type)
411 {
412 case DevicePowerState:
413 switch (pIrpSp->Parameters.Power.State.DeviceState)
414 {
415 case PowerDeviceD0:
416 break;
417 }
418 break;
419 }
420 break;
421 }
422 }
423 }
424
425 return STATUS_SUCCESS;
426}
427
428
429/**
430 * Handle the Power requests.
431 *
432 * @returns NT status code
433 * @param pDevObj device object
434 * @param pIrp IRP
435 */
436NTSTATUS vbgdNtPower(PDEVICE_OBJECT pDevObj, PIRP pIrp)
437{
438 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
439 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
440 POWER_STATE_TYPE powerType;
441 POWER_STATE powerState;
442 POWER_ACTION powerAction;
443
444 Log(("VBoxGuest::vbgdNtGuestPower\n"));
445
446 powerType = pStack->Parameters.Power.Type;
447 powerAction = pStack->Parameters.Power.ShutdownType;
448 powerState = pStack->Parameters.Power.State;
449
450 switch (pStack->MinorFunction)
451 {
452 case IRP_MN_SET_POWER:
453 {
454 Log(("VBoxGuest::vbgdNtGuestPower: IRP_MN_SET_POWER, type= %d\n", powerType));
455 switch (powerType)
456 {
457 case SystemPowerState:
458 {
459 Log(("VBoxGuest::vbgdNtGuestPower: SystemPowerState, action = %d, state = %d\n", powerAction, powerState));
460
461 switch (powerAction)
462 {
463 case PowerActionSleep:
464
465 /* System now is in a working state. */
466 if (powerState.SystemState == PowerSystemWorking)
467 {
468 if ( pDevExt
469 && pDevExt->win.s.LastSystemPowerAction == PowerActionHibernate)
470 {
471 Log(("VBoxGuest::vbgdNtGuestPower: Returning from hibernation!\n"));
472 int rc = VBoxGuestReinitDevExtAfterHibernation(pDevExt,
473 vbgdNtVersionToOSType(g_enmVbgdNtVer));
474 if (RT_FAILURE(rc))
475 Log(("VBoxGuest::vbgdNtGuestPower: Cannot re-init VMMDev chain, rc = %d!\n", rc));
476 }
477 }
478 break;
479
480 case PowerActionShutdownReset:
481 {
482 Log(("VBoxGuest::vbgdNtGuestPower: Power action reset!\n"));
483
484 /* Tell the VMM that we no longer support mouse pointer integration. */
485 VMMDevReqMouseStatus *pReq = NULL;
486 int vrc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof (VMMDevReqMouseStatus), VMMDevReq_SetMouseStatus);
487 if (RT_SUCCESS(vrc))
488 {
489 pReq->mouseFeatures = 0;
490 pReq->pointerXPos = 0;
491 pReq->pointerYPos = 0;
492
493 vrc = VbglGRPerform(&pReq->header);
494 if (RT_FAILURE(vrc))
495 {
496 Log(("VBoxGuest::PowerStateRequest: error communicating new power status to VMMDev. "
497 "vrc = %Rrc\n", vrc));
498 }
499
500 VbglGRFree(&pReq->header);
501 }
502
503 /* Don't do any cleanup here; there might be still coming in some IOCtls after we got this
504 * power action and would assert/crash when we already cleaned up all the stuff! */
505 break;
506 }
507
508 case PowerActionShutdown:
509 case PowerActionShutdownOff:
510 {
511 Log(("VBoxGuest::vbgdNtGuestPower: Power action shutdown!\n"));
512 if (powerState.SystemState >= PowerSystemShutdown)
513 {
514 Log(("VBoxGuest::vbgdNtGuestPower: Telling the VMMDev to close the VM ...\n"));
515
516 VMMDevPowerStateRequest *pReq = pDevExt->win.s.pPowerStateRequest;
517 int vrc = VERR_NOT_IMPLEMENTED;
518 if (pReq)
519 {
520 pReq->header.requestType = VMMDevReq_SetPowerStatus;
521 pReq->powerState = VMMDevPowerState_PowerOff;
522
523 vrc = VbglGRPerform(&pReq->header);
524 }
525 if (RT_FAILURE(vrc))
526 {
527 Log(("VBoxGuest::PowerStateRequest: Error communicating new power status to VMMDev. "
528 "vrc = %Rrc\n", vrc));
529 }
530
531 /* No need to do cleanup here; at this point we should've been
532 * turned off by VMMDev already! */
533 }
534 break;
535 }
536
537 case PowerActionHibernate:
538
539 Log(("VBoxGuest::vbgdNtGuestPower: Power action hibernate!\n"));
540 break;
541 }
542
543 /*
544 * Save the current system power action for later use.
545 * This becomes handy when we return from hibernation for example.
546 */
547 if (pDevExt)
548 pDevExt->win.s.LastSystemPowerAction = powerAction;
549
550 break;
551 }
552 default:
553 break;
554 }
555 break;
556 }
557 default:
558 break;
559 }
560
561 /*
562 * Whether we are completing or relaying this power IRP,
563 * we must call PoStartNextPowerIrp.
564 */
565 PoStartNextPowerIrp(pIrp);
566
567 /*
568 * Send the IRP down the driver stack,
569 * using PoCallDriver (not IoCallDriver, as for non-power irps).
570 */
571 IoCopyCurrentIrpStackLocationToNext(pIrp);
572 IoSetCompletionRoutine(pIrp,
573 vbgdNtPowerComplete,
574 (PVOID)pDevExt,
575 TRUE,
576 TRUE,
577 TRUE);
578 return PoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp);
579}
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