VirtualBox

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

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

Additions/win: no need to check the rc of the request header after VbglGRPerform()

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