VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/VBoxGuest/VBoxGuestPnP.cpp@ 31364

Last change on this file since 31364 was 31364, checked in by vboxsync, 15 years ago

Some more fixes for Guest Additions version lookup/status; moved some duplicate helper function to VbglR0.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.9 KB
Line 
1/** @file
2 *
3 * VBoxGuest -- VirtualBox Win32 guest support driver PnP code
4 *
5 * Copyright (C) 2006-2007 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// enable backdoor logging
17//#define LOG_ENABLED
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#include "VBoxGuestPnP.h"
23#include "Helper.h"
24#include <VBox/err.h>
25
26#include <VBox/VBoxGuestLib.h>
27
28/*******************************************************************************
29* Defined Constants And Macros *
30*******************************************************************************/
31
32
33extern "C"
34{
35static NTSTATUS sendIrpSynchronously(PDEVICE_OBJECT pDevObj, PIRP pIrp, BOOLEAN fStrict);
36static NTSTATUS pnpIrpComplete(PDEVICE_OBJECT pDevObj, PIRP pIrp, PKEVENT event);
37static VOID showDeviceResources(PCM_PARTIAL_RESOURCE_LIST pResourceList);
38}
39
40#ifdef ALLOC_PRAGMA
41#pragma alloc_text (PAGE, VBoxGuestPnP)
42#pragma alloc_text (PAGE, VBoxGuestPower)
43#pragma alloc_text (PAGE, sendIrpSynchronously)
44#pragma alloc_text (PAGE, showDeviceResources)
45#endif
46
47/* reenable logging, this was #undef'ed on iprt/log.h for RING0 */
48#define LOG_ENABLED
49
50/*******************************************************************************
51* Internal Functions *
52*******************************************************************************/
53
54/**
55 * Irp completion routine for PnP Irps we send.
56 *
57 * @param pDevObj Device object.
58 * @param pIrp Request packet.
59 * @param event Semaphore.
60 * @return NT status code
61 */
62static NTSTATUS pnpIrpComplete(PDEVICE_OBJECT pDevObj, PIRP pIrp, PKEVENT event)
63{
64 KeSetEvent(event, 0, FALSE);
65 return STATUS_MORE_PROCESSING_REQUIRED;
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 sendIrpSynchronously(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)pnpIrpComplete, &event, TRUE, TRUE, TRUE);
84
85 NTSTATUS rc = IoCallDriver(pDevObj, pIrp);
86
87 if (rc == STATUS_PENDING)
88 {
89 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
90 rc = pIrp->IoStatus.Status;
91 }
92
93 if (!fStrict
94 && (rc == STATUS_NOT_SUPPORTED || rc == STATUS_INVALID_DEVICE_REQUEST))
95 {
96 rc = STATUS_SUCCESS;
97 }
98
99 dprintf(("VBoxGuest::sendIrpSynchronously: returning 0x%x\n", rc));
100
101 return rc;
102}
103
104
105/**
106 * PnP Request handler.
107 *
108 * @param pDevObj Device object.
109 * @param pIrp Request packet.
110 */
111NTSTATUS VBoxGuestPnP(PDEVICE_OBJECT pDevObj, PIRP pIrp)
112{
113 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
114 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
115 NTSTATUS rc = STATUS_SUCCESS;
116
117#ifdef LOG_ENABLED
118 static char* fcnname[] =
119 {
120 "IRP_MN_START_DEVICE",
121 "IRP_MN_QUERY_REMOVE_DEVICE",
122 "IRP_MN_REMOVE_DEVICE",
123 "IRP_MN_CANCEL_REMOVE_DEVICE",
124 "IRP_MN_STOP_DEVICE",
125 "IRP_MN_QUERY_STOP_DEVICE",
126 "IRP_MN_CANCEL_STOP_DEVICE",
127 "IRP_MN_QUERY_DEVICE_RELATIONS",
128 "IRP_MN_QUERY_INTERFACE",
129 "IRP_MN_QUERY_CAPABILITIES",
130 "IRP_MN_QUERY_RESOURCES",
131 "IRP_MN_QUERY_RESOURCE_REQUIREMENTS",
132 "IRP_MN_QUERY_DEVICE_TEXT",
133 "IRP_MN_FILTER_RESOURCE_REQUIREMENTS",
134 "",
135 "IRP_MN_READ_CONFIG",
136 "IRP_MN_WRITE_CONFIG",
137 "IRP_MN_EJECT",
138 "IRP_MN_SET_LOCK",
139 "IRP_MN_QUERY_ID",
140 "IRP_MN_QUERY_PNP_DEVICE_STATE",
141 "IRP_MN_QUERY_BUS_INFORMATION",
142 "IRP_MN_DEVICE_USAGE_NOTIFICATION",
143 "IRP_MN_SURPRISE_REMOVAL",
144 };
145 dprintf(("VBoxGuest::VBoxGuestPnp: MinorFunction: %s\n", pStack->MinorFunction < (sizeof(fcnname)/sizeof(fcnname[0])) ? fcnname[pStack->MinorFunction] : "unknown"));
146#endif
147 switch (pStack->MinorFunction)
148 {
149 case IRP_MN_START_DEVICE:
150 {
151 rc = sendIrpSynchronously(pDevExt->nextLowerDriver, pIrp, TRUE);
152
153 if (NT_SUCCESS(rc) && NT_SUCCESS(pIrp->IoStatus.Status))
154 {
155 dprintf(("VBoxGuest::START_DEVICE: pStack->Parameters.StartDevice.AllocatedResources = %p\n", pStack->Parameters.StartDevice.AllocatedResources));
156
157 if (!pStack->Parameters.StartDevice.AllocatedResources)
158 {
159 dprintf(("VBoxGuest::START_DEVICE: no resources, pDevExt = %p, nextLowerDriver = %p!!!\n", pDevExt, pDevExt? pDevExt->nextLowerDriver: NULL));
160 rc = STATUS_UNSUCCESSFUL;
161 }
162 else
163 {
164 showDeviceResources(&pStack->Parameters.StartDevice.AllocatedResources->List[0].PartialResourceList);
165
166 VBoxScanPCIResourceList(pStack->Parameters.StartDevice.AllocatedResourcesTranslated,
167 pDevExt);
168
169 /** @todo cleanup and merging codepath with NT */
170 int rcVBox;
171 rcVBox = VbglInit (pDevExt->startPortAddress, pDevExt->pVMMDevMemory);
172 if (!RT_SUCCESS(rcVBox))
173 {
174 dprintf(("VBoxGuest::START_DEVICE: VbglInit failed. rcVBox = %d\n", rcVBox));
175 rc = STATUS_UNSUCCESSFUL;
176 }
177
178 if (NT_SUCCESS(rc))
179 {
180 rcVBox = VbglGRAlloc ((VMMDevRequestHeader **)&pDevExt->irqAckEvents, sizeof (VMMDevEvents), VMMDevReq_AcknowledgeEvents);
181 if (!RT_SUCCESS(rc))
182 {
183 dprintf(("VBoxGuest::START_DEVICE: VbglAlloc failed for irqAckEvents. rcVBox = %d\n", rcVBox));
184 rc = STATUS_UNSUCCESSFUL;
185 }
186 }
187
188 if (NT_SUCCESS(rc))
189 {
190 rcVBox = VbglGRAlloc ((VMMDevRequestHeader **)&pDevExt->powerStateRequest, sizeof (VMMDevPowerStateRequest), VMMDevReq_SetPowerStatus);
191 if (!RT_SUCCESS(rc))
192 {
193 dprintf(("VBoxGuest::START_DEVICE: VbglAlloc failed for powerStateRequest. rcVBox = %d\n", rcVBox));
194 rc = STATUS_UNSUCCESSFUL;
195 }
196 }
197
198 if (NT_SUCCESS(rc))
199 {
200 // Map physical address of VMMDev memory
201 rc = hlpVBoxMapVMMDevMemory(pDevExt);
202 if (!NT_SUCCESS(rc))
203 {
204 dprintf(("VBoxGuest::START_DEVICE: can't map physical memory, rc = %d\n", rc));
205 }
206 }
207
208 if (NT_SUCCESS(rc))
209 {
210 // register DPC and ISR
211 dprintf(("VBoxGuest::VBoxGuestPnp: initializing DPC...\n"));
212 IoInitializeDpcRequest(pDevExt->deviceObject, VBoxGuestDpcHandler);
213
214 rc = IoConnectInterrupt(&pDevExt->interruptObject, // out: interrupt object
215 (PKSERVICE_ROUTINE)VBoxGuestIsrHandler, // ISR
216 pDevExt, // context
217 NULL, // optional spinlock
218 pDevExt->interruptVector, // interrupt vector
219 (KIRQL)pDevExt->interruptLevel, // interrupt level
220 (KIRQL)pDevExt->interruptLevel, // interrupt level
221 pDevExt->interruptMode, // LevelSensitive or Latched
222 TRUE, // shareable interrupt
223 pDevExt->interruptAffinity, // CPU affinity
224 FALSE); // don't save FPU stack
225 if (!NT_SUCCESS(rc))
226 {
227 dprintf(("VBoxGuest::VBoxGuestPnp: could not connect interrupt: rc = 0x%x\n", rc));
228 }
229 }
230 }
231 }
232 if (NT_SUCCESS(rc))
233 {
234 createThreads(pDevExt);
235
236 // initialize the event notification semaphore
237 KeInitializeEvent(&pDevExt->keventNotification, NotificationEvent, FALSE);
238
239 /* Preallocated constant timeout 250ms for HGCM async waiter. */
240 pDevExt->HGCMWaitTimeout.QuadPart = 250;
241 pDevExt->HGCMWaitTimeout.QuadPart *= -10000; /* relative in 100ns units */
242
243 int vrc = VBoxInitMemBalloon(pDevExt);
244 if (RT_SUCCESS(vrc))
245 {
246 vrc = VbglR0MiscReportGuestInfo(hlpVBoxWinVersionToOSType(winVersion));
247 if (RT_FAILURE(vrc))
248 dprintf(("VBoxGuest::VBoxGuestPnp::IRP_MN_START_DEVICE: could not report information to host, rc = %d\n", rc));
249 }
250
251 // ready to rumble!
252 dprintf(("VBoxGuest::VBoxGuestPnp: device is ready!\n"));
253 pDevExt->devState = WORKING;
254 } else
255 {
256 dprintf(("VBoxGuest::VBoxGuestPnp: error: rc = 0x%x\n", rc));
257
258 // need to unmap memory in case of errors
259 hlpVBoxUnmapVMMDevMemory (pDevExt);
260 }
261 pIrp->IoStatus.Status = rc;
262 pIrp->IoStatus.Information = 0;
263 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
264 break;
265 }
266
267 case IRP_MN_QUERY_REMOVE_DEVICE:
268 {
269#ifdef VBOX_REBOOT_ON_UNINSTALL
270 /* The device can not be removed without a reboot. */
271 if (pDevExt->devState == WORKING)
272 {
273 pDevExt->devState = PENDINGREMOVE;
274 }
275 pIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
276 pIrp->IoStatus.Information = 0;
277 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
278 rc = STATUS_UNSUCCESSFUL;
279
280 dprintf(("VBoxGuest::VBoxGuestPnp: refuse with rc = %p\n", pIrp->IoStatus.Status));
281#else
282 pIrp->IoStatus.Status = STATUS_SUCCESS;
283 if (pDevExt->devState == WORKING)
284 {
285 pDevExt->devState = PENDINGREMOVE;
286 }
287 IoSkipCurrentIrpStackLocation(pIrp);
288 rc = IoCallDriver(pDevExt->nextLowerDriver, pIrp);
289#endif /* VBOX_REBOOT_ON_UNINSTALL */
290 break;
291 }
292
293 case IRP_MN_REMOVE_DEVICE:
294 {
295 /* @todo merge Remove and Stop, make a helper for common actions */
296 pIrp->IoStatus.Status = STATUS_SUCCESS;
297
298 unreserveHypervisorMemory(pDevExt);
299
300 if (pDevExt->workerThread)
301 {
302 dprintf(("VBoxGuest::VBoxGuestPnp: waiting for the worker thread to terminate...\n"));
303 pDevExt->stopThread = TRUE;
304 KeSetEvent(&pDevExt->workerThreadRequest, 0, FALSE);
305 KeWaitForSingleObject(pDevExt->workerThread,
306 Executive, KernelMode, FALSE, NULL);
307 dprintf(("VBoxGuest::VBoxGuestPnp: returned from KeWaitForSingleObject for worker thread\n"));
308 }
309
310 if (pDevExt->idleThread)
311 {
312 dprintf(("VBoxGuest::VBoxGuestPnp: waiting for the idle thread to terminate...\n"));
313 pDevExt->stopThread = TRUE;
314 KeWaitForSingleObject(pDevExt->idleThread,
315 Executive, KernelMode, FALSE, NULL);
316 dprintf(("VBoxGuest::VBoxGuestPnp: returned from KeWaitForSingleObject for idle thread\n"));
317 }
318
319 VbglTerminate ();
320
321 // according to MSDN we have to unmap previously mapped memory
322 hlpVBoxUnmapVMMDevMemory (pDevExt);
323
324 /* Free the memory balloon (if any) */
325 VBoxCleanupMemBalloon(pDevExt);
326
327 if (pDevExt->nextLowerDriver != NULL)
328 {
329 IoDetachDevice(pDevExt->nextLowerDriver);
330 }
331
332#ifdef VBOX_WITH_HGCM
333 if (pDevExt->SessionSpinlock != NIL_RTSPINLOCK)
334 RTSpinlockDestroy(pDevExt->SessionSpinlock);
335#endif
336
337 UNICODE_STRING win32Name;
338 RtlInitUnicodeString(&win32Name, VBOXGUEST_DEVICE_NAME_DOS);
339 IoDeleteSymbolicLink(&win32Name);
340 IoDeleteDevice(pDevObj);
341 pDevExt->devState = REMOVED;
342 IoSkipCurrentIrpStackLocation(pIrp);
343 rc = IoCallDriver(pDevExt->nextLowerDriver, pIrp);
344 break;
345 }
346
347 case IRP_MN_QUERY_STOP_DEVICE:
348 {
349#ifdef VBOX_REBOOT_ON_UNINSTALL
350 dprintf(("VBoxGuest::VBoxGuestPnp: refuse\n"));
351 /* The device can not be stopped without a reboot. */
352 if (pDevExt->devState == WORKING)
353 {
354 pDevExt->devState = PENDINGSTOP;
355 }
356 pIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
357 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
358 rc = STATUS_UNSUCCESSFUL;
359#else
360 pIrp->IoStatus.Status = STATUS_SUCCESS;
361 if (pDevExt->devState == WORKING)
362 {
363 pDevExt->devState = PENDINGSTOP;
364 }
365 IoSkipCurrentIrpStackLocation(pIrp);
366 rc = IoCallDriver(pDevExt->nextLowerDriver, pIrp);
367#endif /* VBOX_REBOOT_ON_UNINSTALL */
368 break;
369 }
370
371 case IRP_MN_STOP_DEVICE:
372 {
373 pIrp->IoStatus.Status = STATUS_SUCCESS;
374 if (pDevExt->devState == PENDINGSTOP)
375 {
376 VbglTerminate ();
377
378 // according to MSDN we have to unmap previously mapped memory
379 hlpVBoxUnmapVMMDevMemory (pDevExt);
380
381 pDevExt->devState = STOPPED;
382 dprintf(("VBoxGuest::VBoxGuestPnp: device has been disabled\n"));
383 } else
384 {
385 dprintf(("VBoxGuest::VBoxGuestPnp: devState not PENDINGSTOP but %d\n", pDevExt->devState));
386 }
387 IoSkipCurrentIrpStackLocation(pIrp);
388 rc = IoCallDriver(pDevExt->nextLowerDriver, pIrp);
389 break;
390 }
391
392 default:
393 {
394 IoSkipCurrentIrpStackLocation(pIrp);
395 rc = IoCallDriver(pDevExt->nextLowerDriver, pIrp);
396 }
397
398 }
399 return rc;
400}
401
402
403/**
404 * Debug helper to dump a device resource list.
405 *
406 * @param pResourceList list of device resources.
407 */
408static VOID showDeviceResources(PCM_PARTIAL_RESOURCE_LIST pResourceList)
409{
410#ifdef LOG_ENABLED
411 PCM_PARTIAL_RESOURCE_DESCRIPTOR resource = pResourceList->PartialDescriptors;
412 ULONG nres = pResourceList->Count;
413 ULONG i;
414
415 for (i = 0; i < nres; ++i, ++resource)
416 {
417 ULONG type = resource->Type;
418
419 static char* name[] =
420 {
421 "CmResourceTypeNull",
422 "CmResourceTypePort",
423 "CmResourceTypeInterrupt",
424 "CmResourceTypeMemory",
425 "CmResourceTypeDma",
426 "CmResourceTypeDeviceSpecific",
427 "CmResourceTypeBusNumber",
428 "CmResourceTypeDevicePrivate",
429 "CmResourceTypeAssignedResource",
430 "CmResourceTypeSubAllocateFrom",
431 };
432
433 dprintf(("VBoxGuest::showDeviceResources: type %s", type < (sizeof(name)/sizeof(name[0])) ? name[type] : "unknown"));
434
435 switch (type)
436 {
437 case CmResourceTypePort:
438 case CmResourceTypeMemory:
439 dprintf(("VBoxGuest::showDeviceResources: start %8X%8.8lX length %X\n",
440 resource->u.Port.Start.HighPart, resource->u.Port.Start.LowPart,
441 resource->u.Port.Length));
442 break;
443
444 case CmResourceTypeInterrupt:
445 dprintf(("VBoxGuest::showDeviceResources: level %X, vector %X, affinity %X\n",
446 resource->u.Interrupt.Level, resource->u.Interrupt.Vector,
447 resource->u.Interrupt.Affinity));
448 break;
449
450 case CmResourceTypeDma:
451 dprintf(("VBoxGuest::showDeviceResources: channel %d, port %X\n",
452 resource->u.Dma.Channel, resource->u.Dma.Port));
453 break;
454
455 default:
456 dprintf(("\n"));
457 break;
458 }
459 }
460#endif
461}
462
463/**
464 * Handle the power completion event.
465 *
466 * @returns NT status code
467 * @param devObj targetted device object
468 * @param irp IO request packet
469 * @param context context value passed to IoSetCompletionRoutine in VBoxGuestPower
470 */
471NTSTATUS VBoxGuestPowerComplete(IN PDEVICE_OBJECT devObj,
472 IN PIRP irp, IN PVOID context)
473{
474 PIO_STACK_LOCATION irpSp;
475 PVBOXGUESTDEVEXT devExt = (PVBOXGUESTDEVEXT)context;
476
477 ASSERT(devExt);
478 ASSERT(devExt->signature == DEVICE_EXTENSION_SIGNATURE);
479
480 irpSp = IoGetCurrentIrpStackLocation(irp);
481 ASSERT(irpSp->MajorFunction == IRP_MJ_POWER);
482
483 if (NT_SUCCESS(irp->IoStatus.Status))
484 {
485 switch (irpSp->MinorFunction)
486 {
487 case IRP_MN_SET_POWER:
488
489 switch (irpSp->Parameters.Power.Type)
490 {
491 case DevicePowerState:
492 switch (irpSp->Parameters.Power.State.DeviceState)
493 {
494 case PowerDeviceD0:
495 break;
496 }
497 break;
498 }
499 break;
500 }
501 }
502
503 return STATUS_SUCCESS;
504}
505
506
507/**
508 * Handle the Power requests.
509 *
510 * @returns NT status code
511 * @param pDevObj device object
512 * @param pIrp IRP
513 */
514NTSTATUS VBoxGuestPower(PDEVICE_OBJECT pDevObj, PIRP pIrp)
515{
516 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
517 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
518 POWER_STATE_TYPE powerType;
519 POWER_STATE powerState;
520 POWER_ACTION powerAction;
521
522 dprintf(("VBoxGuest::VBoxGuestPower\n"));
523
524 powerType = pStack->Parameters.Power.Type;
525 powerAction = pStack->Parameters.Power.ShutdownType;
526 powerState = pStack->Parameters.Power.State;
527
528 switch (pStack->MinorFunction)
529 {
530 case IRP_MN_SET_POWER:
531 {
532 dprintf(("VBoxGuest::VBoxGuestPower: IRP_MN_SET_POWER\n"));
533 switch (powerType)
534 {
535 case SystemPowerState:
536 {
537 dprintf(("VBoxGuest::VBoxGuestPower: SystemPowerState\n"));
538 switch (powerAction)
539 {
540 case PowerActionShutdownReset:
541 {
542 dprintf(("VBoxGuest::VBoxGuestPower: power action reset!\n"));
543 /* tell the VMM that we no longer support mouse pointer integration */
544
545 VMMDevReqMouseStatus *req = NULL;
546
547 int rc = VbglGRAlloc ((VMMDevRequestHeader **)&req, sizeof (VMMDevReqMouseStatus), VMMDevReq_SetMouseStatus);
548
549 if (RT_SUCCESS(rc))
550 {
551 req->mouseFeatures = 0;
552 req->pointerXPos = 0;
553 req->pointerYPos = 0;
554
555 rc = VbglGRPerform (&req->header);
556
557 if (RT_FAILURE(rc))
558 {
559 dprintf(("VBoxGuest::PowerStateRequest: error communicating new power status to VMMDev. "
560 "rc = %Rrc\n", rc));
561 }
562
563 VbglGRFree (&req->header);
564 }
565 break;
566 }
567
568 case PowerActionShutdown:
569 case PowerActionShutdownOff:
570 {
571 dprintf(("VBoxGuest::VBoxGuestPower: power action shutdown!\n"));
572 if (powerState.SystemState >= PowerSystemShutdown)
573 {
574 dprintf(("VBoxGuest::VBoxGuestPower: Telling the VMMDev to close the VM...\n"));
575
576 if (pDevExt && pDevExt->powerStateRequest)
577 {
578 VMMDevPowerStateRequest *req = pDevExt->powerStateRequest;
579
580 req->header.requestType = VMMDevReq_SetPowerStatus;
581 req->powerState = VMMDevPowerState_PowerOff;
582
583 int rc = VbglGRPerform (&req->header);
584
585 if (RT_FAILURE(rc))
586 {
587 dprintf(("VBoxGuest::PowerStateRequest: error communicating new power status to VMMDev. "
588 "rc = %Rrc\n", rc));
589 }
590 }
591 }
592 break;
593 }
594 }
595 break;
596 }
597 default:
598 break;
599 }
600 break;
601 }
602 default:
603 break;
604 }
605
606 /*
607 * Whether we are completing or relaying this power IRP,
608 * we must call PoStartNextPowerIrp.
609 */
610 PoStartNextPowerIrp(pIrp);
611
612 /*
613 * Send the IRP down the driver stack,
614 * using PoCallDriver (not IoCallDriver, as for non-power irps).
615 */
616 IoCopyCurrentIrpStackLocationToNext(pIrp);
617 IoSetCompletionRoutine(pIrp,
618 VBoxGuestPowerComplete,
619 (PVOID)pDevExt,
620 TRUE,
621 TRUE,
622 TRUE);
623 return PoCallDriver(pDevExt->nextLowerDriver, pIrp);
624}
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