VirtualBox

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

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

VBoxGuest: Build fix (untested).

  • 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 45013 2013-03-13 08:42: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 pEvent 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 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(("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->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->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->pNextLowerDriver, pIrp, TRUE);
185
186 if (NT_SUCCESS(rc) && pDevExt->devState == PENDINGREMOVE)
187 {
188 /* Return to the state prior to receiving the IRP_MN_QUERY_REMOVE_DEVICE request. */
189 pDevExt->devState = pDevExt->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->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->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 * Update/bird: vbgdNtCleanup actually does that... So, what's there to do? */
258 rc = vbgdNtCleanup(pDevObj);
259 Log(("VBoxGuest::vbgdNtGuestPnp: REMOVE_DEVICE: vbgdNtCleanup 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(("VBoxGuest::vbgdNtGuestPnp: REMOVE_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
272
273 IoDetachDevice(pDevExt->pNextLowerDriver);
274
275 Log(("VBoxGuest::vbgdNtGuestPnp: REMOVE_DEVICE: Removing device ...\n"));
276
277 /* Destroy device extension and clean up everything else. */
278 VBoxGuestDeleteDevExt(&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(("VBoxGuest::vbgdNtGuestPnp: 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(("VBoxGuest::vbgdNtGuestPnp: 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(("VBoxGuest::vbgdNtVBoxGuestPnP: CANCEL_STOP_DEVICE\n"));
300
301 /* This must be handled first by the lower driver. */
302 rc = vbgdNtSendIrpSynchronously(pDevExt->pNextLowerDriver, pIrp, TRUE);
303
304 if (NT_SUCCESS(rc) && pDevExt->devState == PENDINGSTOP)
305 {
306 /* Return to the state prior to receiving the IRP_MN_QUERY_STOP_DEVICE request. */
307 pDevExt->devState = pDevExt->prevDevState;
308 }
309
310 /* Complete the IRP. */
311 break;
312 }
313
314 case IRP_MN_QUERY_STOP_DEVICE:
315 {
316 Log(("VBoxGuest::vbgdNtVBoxGuestPnP: QUERY_STOP_DEVICE\n"));
317
318#ifdef VBOX_REBOOT_ON_UNINSTALL
319 Log(("VBoxGuest::vbgdNtGuestPnp: 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, 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(("VBoxGuest::vbgdNtGuestPnp: 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(("VBoxGuest::vbgdNtVBoxGuestPnP: STOP_DEVICE\n"));
348
349 VBOXGUEST_UPDATE_DEVSTATE(pDevExt, STOPPED);
350
351 /* Free hardware resources. */
352 /** @todo this should actually free I/O ports, interrupts, etc.
353 * Update/bird: vbgdNtCleanup actually does that... So, what's there to do? */
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->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->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#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
409 switch (pIrpSp->Parameters.Power.Type)
410 {
411 case DevicePowerState:
412 switch (pIrpSp->Parameters.Power.State.DeviceState)
413 {
414 case PowerDeviceD0:
415 break;
416 }
417 break;
418 }
419 break;
420 }
421 }
422 }
423#endif
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 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
440 POWER_STATE_TYPE enmPowerType = pStack->Parameters.Power.Type;
441 POWER_STATE PowerState = pStack->Parameters.Power.State;
442 POWER_ACTION enmPowerAction = pStack->Parameters.Power.ShutdownType;
443
444 Log(("VBoxGuest::vbgdNtGuestPower\n"));
445
446 switch (pStack->MinorFunction)
447 {
448 case IRP_MN_SET_POWER:
449 {
450 Log(("VBoxGuest::vbgdNtGuestPower: IRP_MN_SET_POWER, type= %d\n", enmPowerType));
451 switch (enmPowerType)
452 {
453 case SystemPowerState:
454 {
455 Log(("VBoxGuest::vbgdNtGuestPower: SystemPowerState, action = %d, state = %d/%d\n",
456 enmPowerAction, PowerState.SystemState, PowerState.DeviceState));
457
458 switch (enmPowerAction)
459 {
460 case PowerActionSleep:
461
462 /* System now is in a working state. */
463 if (PowerState.SystemState == PowerSystemWorking)
464 {
465 if ( pDevExt
466 && pDevExt->LastSystemPowerAction == PowerActionHibernate)
467 {
468 Log(("VBoxGuest::vbgdNtGuestPower: Returning from hibernation!\n"));
469 int rc = VBoxGuestReinitDevExtAfterHibernation(&pDevExt->Core,
470 vbgdNtVersionToOSType(g_enmVbgdNtVer));
471 if (RT_FAILURE(rc))
472 Log(("VBoxGuest::vbgdNtGuestPower: Cannot re-init VMMDev chain, rc = %d!\n", rc));
473 }
474 }
475 break;
476
477 case PowerActionShutdownReset:
478 {
479 Log(("VBoxGuest::vbgdNtGuestPower: 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),
484 VMMDevReq_SetMouseStatus);
485 if (RT_SUCCESS(vrc))
486 {
487 pReq->mouseFeatures = 0;
488 pReq->pointerXPos = 0;
489 pReq->pointerYPos = 0;
490
491 vrc = VbglGRPerform(&pReq->header);
492 if (RT_FAILURE(vrc))
493 {
494 Log(("VBoxGuest::PowerStateRequest: error communicating new power status to VMMDev. 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::vbgdNtGuestPower: Power action shutdown!\n"));
509 if (PowerState.SystemState >= PowerSystemShutdown)
510 {
511 Log(("VBoxGuest::vbgdNtGuestPower: Telling the VMMDev to close the VM ...\n"));
512
513 VMMDevPowerStateRequest *pReq = pDevExt->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 Log(("VBoxGuest::PowerStateRequest: Error communicating new power status to VMMDev. vrc = %Rrc\n", vrc));
524
525 /* No need to do cleanup here; at this point we should've been
526 * turned off by VMMDev already! */
527 }
528 break;
529 }
530
531 case PowerActionHibernate:
532
533 Log(("VBoxGuest::vbgdNtGuestPower: Power action hibernate!\n"));
534 break;
535 }
536
537 /*
538 * Save the current system power action for later use.
539 * This becomes handy when we return from hibernation for example.
540 */
541 if (pDevExt)
542 pDevExt->LastSystemPowerAction = enmPowerAction;
543
544 break;
545 }
546 default:
547 break;
548 }
549 break;
550 }
551 default:
552 break;
553 }
554
555 /*
556 * Whether we are completing or relaying this power IRP,
557 * we must call PoStartNextPowerIrp.
558 */
559 PoStartNextPowerIrp(pIrp);
560
561 /*
562 * Send the IRP down the driver stack, using PoCallDriver
563 * (not IoCallDriver, as for non-power irps).
564 */
565 IoCopyCurrentIrpStackLocationToNext(pIrp);
566 IoSetCompletionRoutine(pIrp,
567 vbgdNtPowerComplete,
568 (PVOID)pDevExt,
569 TRUE,
570 TRUE,
571 TRUE);
572 return PoCallDriver(pDevExt->pNextLowerDriver, pIrp);
573}
574
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