VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/xpdm/VBoxMPInternal.cpp@ 55210

Last change on this file since 55210 was 53008, checked in by vboxsync, 10 years ago

include,Additions: Windows 10 tweaks.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.1 KB
Line 
1/* $Id: VBoxMPInternal.cpp 53008 2014-10-09 11:34:57Z vboxsync $ */
2
3/** @file
4 * VBox XPDM Miniport internal functions
5 */
6
7/*
8 * Copyright (C) 2011 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19#include "VBoxMPInternal.h"
20#include <VBox/VBoxVideo.h>
21#include <VBox/VBoxGuestLib.h>
22#include <iprt/asm.h>
23
24typedef struct _VBVAMINIPORT_CHANNELCONTEXT
25{
26 PFNHGSMICHANNELHANDLER pfnChannelHandler;
27 void *pvChannelHandler;
28} VBVAMINIPORT_CHANNELCONTEXT;
29
30typedef struct _VBVADISP_CHANNELCONTEXT
31{
32 /** The generic command handler builds up a list of commands - in reverse
33 * order! - here */
34 VBVAHOSTCMD *pCmd;
35 bool bValid;
36} VBVADISP_CHANNELCONTEXT;
37
38typedef struct _VBVA_CHANNELCONTEXTS
39{
40 PVBOXMP_COMMON pCommon;
41 uint32_t cUsed;
42 uint32_t cContexts;
43 VBVAMINIPORT_CHANNELCONTEXT mpContext;
44 VBVADISP_CHANNELCONTEXT aContexts[1];
45} VBVA_CHANNELCONTEXTS;
46
47/* Computes the size of a framebuffer. DualView has a few framebuffers of the computed size. */
48static void VBoxComputeFrameBufferSizes(PVBOXMP_DEVEXT pPrimaryExt)
49{
50 PVBOXMP_COMMON pCommon = VBoxCommonFromDeviceExt(pPrimaryExt);
51
52 ULONG ulAvailable = pCommon->cbVRAM - pCommon->cbMiniportHeap - VBVA_ADAPTER_INFORMATION_SIZE;
53 /* Size of a framebuffer. */
54 ULONG ulSize = ulAvailable / pCommon->cDisplays;
55 /* Align down to 4096 bytes. */
56 ulSize &= ~0xFFF;
57
58 LOG(("cbVRAM = 0x%08X, cDisplays = %d, ulSize = 0x%08X, ulSize * cDisplays = 0x%08X, slack = 0x%08X",
59 pCommon->cbVRAM, pCommon->cDisplays,
60 ulSize, ulSize * pCommon->cDisplays,
61 ulAvailable - ulSize * pCommon->cDisplays));
62
63 /* Update the primary info. */
64 pPrimaryExt->u.primary.ulMaxFrameBufferSize = ulSize;
65
66 /* Update the per extension info. */
67 PVBOXMP_DEVEXT pExt = pPrimaryExt;
68 ULONG ulFrameBufferOffset = 0;
69 while (pExt)
70 {
71 pExt->ulFrameBufferOffset = ulFrameBufferOffset;
72 /* That is assigned when a video mode is set. */
73 pExt->ulFrameBufferSize = 0;
74
75 LOG(("[%d] ulFrameBufferOffset 0x%08X", pExt->iDevice, ulFrameBufferOffset));
76
77 ulFrameBufferOffset += pPrimaryExt->u.primary.ulMaxFrameBufferSize;
78
79 pExt = pExt->pNext;
80 }
81}
82
83DECLCALLBACK(int) VBoxVbvaInitInfoDisplayCB(void *pvData, struct VBVAINFOVIEW *p, uint32_t cViews)
84{
85 PVBOXMP_DEVEXT pExt, pPrimaryExt = (PVBOXMP_DEVEXT) pvData;
86 unsigned i;
87
88 for (i=0, pExt=pPrimaryExt; i<cViews && pExt; i++, pExt=pExt->pNext)
89 {
90 p[i].u32ViewIndex = pExt->iDevice;
91 p[i].u32ViewOffset = pExt->ulFrameBufferOffset;
92 p[i].u32ViewSize = pPrimaryExt->u.primary.ulMaxFrameBufferSize;
93
94 /* How much VRAM should be reserved for the guest drivers to use VBVA. */
95 const uint32_t cbReservedVRAM = VBVA_DISPLAY_INFORMATION_SIZE + VBVA_MIN_BUFFER_SIZE;
96
97 p[i].u32MaxScreenSize = p[i].u32ViewSize > cbReservedVRAM?
98 p[i].u32ViewSize - cbReservedVRAM:
99 0;
100 }
101
102 if (i == VBoxCommonFromDeviceExt(pPrimaryExt)->cDisplays && pExt == NULL)
103 {
104 return VINF_SUCCESS;
105 }
106
107 AssertFailed ();
108 return VERR_INTERNAL_ERROR;
109}
110
111void VBoxCreateDisplays(PVBOXMP_DEVEXT pExt, PVIDEO_PORT_CONFIG_INFO pConfigInfo)
112{
113 LOGF_ENTER();
114
115 PVBOXMP_COMMON pCommon = VBoxCommonFromDeviceExt(pExt);
116 VBOXVIDEOPORTPROCS *pAPI = &pExt->u.primary.VideoPortProcs;
117
118 if (pCommon->bHGSMI)
119 {
120 if (pAPI->fSupportedTypes & VBOXVIDEOPORTPROCS_CSD)
121 {
122 PVBOXMP_DEVEXT pPrev = pExt;
123 ULONG iDisplay, cDisplays;
124
125 cDisplays = pCommon->cDisplays;
126 pCommon->cDisplays = 1;
127
128 for (iDisplay=1; iDisplay<cDisplays; ++iDisplay)
129 {
130 PVBOXMP_DEVEXT pSExt = NULL;
131 VP_STATUS rc;
132
133 /* If VIDEO_DUALVIEW_REMOVABLE is passed as the 3rd parameter, then
134 * the guest does not allow to choose the primary screen.
135 */
136 rc = pAPI->pfnCreateSecondaryDisplay(pExt, (PVOID*)&pSExt, 0);
137 VBOXMP_WARN_VPS(rc);
138
139 if (rc != NO_ERROR)
140 {
141 break;
142 }
143 LOG(("created secondary device %p", pSExt));
144
145 pSExt->pNext = NULL;
146 pSExt->pPrimary = pExt;
147 pSExt->iDevice = iDisplay;
148 pSExt->ulFrameBufferOffset = 0;
149 pSExt->ulFrameBufferSize = 0;
150 pSExt->u.secondary.bEnabled = FALSE;
151
152 /* Update the list pointers */
153 pPrev->pNext = pSExt;
154 pPrev = pSExt;
155
156 /* Take the successfully created display into account. */
157 pCommon->cDisplays++;
158 }
159 }
160 else
161 {
162 /* Even though VM could be configured to have multiply monitors,
163 * we can't support it on this windows version.
164 */
165 pCommon->cDisplays = 1;
166 }
167 }
168
169 /* Now when the number of monitors is known and extensions are created,
170 * calculate the layout of framebuffers.
171 */
172 VBoxComputeFrameBufferSizes(pExt);
173
174 /*Report our screen configuration to host*/
175 if (pCommon->bHGSMI)
176 {
177 int rc;
178 rc = VBoxHGSMISendViewInfo(&pCommon->guestCtx, pCommon->cDisplays, VBoxVbvaInitInfoDisplayCB, (void *) pExt);
179
180 if (RT_FAILURE (rc))
181 {
182 WARN(("VBoxHGSMISendViewInfo failed with rc=%#x, HGSMI disabled", rc));
183 pCommon->bHGSMI = FALSE;
184 }
185 }
186
187 LOGF_LEAVE();
188}
189
190static DECLCALLBACK(void) VBoxVbvaFlush(void *pvFlush)
191{
192 LOGF_ENTER();
193
194 PVBOXMP_DEVEXT pExt = (PVBOXMP_DEVEXT)pvFlush;
195 PVBOXMP_DEVEXT pPrimary = pExt? pExt->pPrimary: NULL;
196
197 if (pPrimary)
198 {
199 VMMDevVideoAccelFlush *req = (VMMDevVideoAccelFlush *)pPrimary->u.primary.pvReqFlush;
200
201 if (req)
202 {
203 int rc = VbglGRPerform (&req->header);
204
205 if (RT_FAILURE(rc))
206 {
207 WARN(("rc = %#xrc!", rc));
208 }
209 }
210 }
211 LOGF_LEAVE();
212}
213
214int VBoxVbvaEnable(PVBOXMP_DEVEXT pExt, BOOLEAN bEnable, VBVAENABLERESULT *pResult)
215{
216 int rc = VINF_SUCCESS;
217 LOGF_ENTER();
218
219 VMMDevMemory *pVMMDevMemory = NULL;
220
221 rc = VbglQueryVMMDevMemory (&pVMMDevMemory);
222 if (RT_FAILURE(rc))
223 {
224 WARN(("VbglQueryVMMDevMemory rc = %#xrc", rc));
225 LOGF_LEAVE();
226 return rc;
227 }
228
229 if (pExt->iDevice>0)
230 {
231 PVBOXMP_DEVEXT pPrimary = pExt->pPrimary;
232 LOGF(("skipping non-primary display %d", pExt->iDevice));
233
234 if (bEnable && pPrimary->u.primary.ulVbvaEnabled && pVMMDevMemory)
235 {
236 pResult->pVbvaMemory = &pVMMDevMemory->vbvaMemory;
237 pResult->pfnFlush = VBoxVbvaFlush;
238 pResult->pvFlush = pExt;
239 }
240 else
241 {
242 VideoPortZeroMemory(&pResult, sizeof(VBVAENABLERESULT));
243 }
244
245 LOGF_LEAVE();
246 return rc;
247 }
248
249 /* Allocate the memory block for VMMDevReq_VideoAccelFlush request. */
250 if (pExt->u.primary.pvReqFlush == NULL)
251 {
252 VMMDevVideoAccelFlush *req = NULL;
253
254 rc = VbglGRAlloc((VMMDevRequestHeader **)&req, sizeof(VMMDevVideoAccelFlush), VMMDevReq_VideoAccelFlush);
255
256 if (RT_SUCCESS(rc))
257 {
258 pExt->u.primary.pvReqFlush = req;
259 }
260 else
261 {
262 WARN(("VbglGRAlloc(VMMDevVideoAccelFlush) rc = %#xrc", rc));
263 LOGF_LEAVE();
264 return rc;
265 }
266 }
267
268 ULONG ulEnabled = 0;
269
270 VMMDevVideoAccelEnable *req = NULL;
271 rc = VbglGRAlloc((VMMDevRequestHeader **)&req, sizeof(VMMDevVideoAccelEnable), VMMDevReq_VideoAccelEnable);
272
273 if (RT_SUCCESS(rc))
274 {
275 req->u32Enable = bEnable;
276 req->cbRingBuffer = VBVA_RING_BUFFER_SIZE;
277 req->fu32Status = 0;
278
279 rc = VbglGRPerform(&req->header);
280 if (RT_SUCCESS(rc))
281 {
282 if (req->fu32Status & VBVA_F_STATUS_ACCEPTED)
283 {
284 LOG(("accepted"));
285
286 /* Initialize the result information and VBVA memory. */
287 if (req->fu32Status & VBVA_F_STATUS_ENABLED)
288 {
289 pResult->pVbvaMemory = &pVMMDevMemory->vbvaMemory;
290 pResult->pfnFlush = VBoxVbvaFlush;
291 pResult->pvFlush = pExt;
292 ulEnabled = 1;
293 }
294 else
295 {
296 VideoPortZeroMemory(&pResult, sizeof(VBVAENABLERESULT));
297 }
298 }
299 else
300 {
301 LOG(("rejected"));
302
303 /* Disable VBVA for old hosts. */
304 req->u32Enable = 0;
305 req->cbRingBuffer = VBVA_RING_BUFFER_SIZE;
306 req->fu32Status = 0;
307
308 VbglGRPerform(&req->header);
309
310 rc = VERR_NOT_SUPPORTED;
311 }
312 }
313 else
314 {
315 WARN(("rc = %#xrc", rc));
316 }
317
318 VbglGRFree(&req->header);
319 }
320 else
321 {
322 WARN(("VbglGRAlloc(VMMDevVideoAccelEnable) rc = %#xrc", rc));
323 }
324
325 pExt->u.primary.ulVbvaEnabled = ulEnabled;
326
327 LOGF_LEAVE();
328 return rc;
329}
330
331static VBVADISP_CHANNELCONTEXT* VBoxVbvaFindHandlerInfo(VBVA_CHANNELCONTEXTS *pCallbacks, int iId)
332{
333 if (iId < 0)
334 {
335 return NULL;
336 }
337 else if(pCallbacks->cContexts > (uint32_t)iId)
338 {
339 return &pCallbacks->aContexts[iId];
340 }
341 return NULL;
342}
343
344/* Reverses a NULL-terminated linked list of VBVAHOSTCMD structures. */
345static VBVAHOSTCMD *VBoxVbvaReverseList(VBVAHOSTCMD *pList)
346{
347 VBVAHOSTCMD *pFirst = NULL;
348 while (pList)
349 {
350 VBVAHOSTCMD *pNext = pList;
351 pList = pList->u.pNext;
352 pNext->u.pNext = pFirst;
353 pFirst = pNext;
354 }
355 return pFirst;
356}
357
358DECLCALLBACK(void) VBoxMPHGSMIHostCmdCompleteCB(HVBOXVIDEOHGSMI hHGSMI, struct VBVAHOSTCMD *pCmd)
359{
360 PHGSMIHOSTCOMMANDCONTEXT pCtx = &((PVBOXMP_COMMON)hHGSMI)->hostCtx;
361 VBoxHGSMIHostCmdComplete(pCtx, pCmd);
362}
363
364DECLCALLBACK(int)
365VBoxMPHGSMIHostCmdRequestCB(HVBOXVIDEOHGSMI hHGSMI, uint8_t u8Channel, uint32_t iDisplay, struct VBVAHOSTCMD **ppCmd)
366{
367 LOGF_ENTER();
368
369 if (!ppCmd)
370 {
371 LOGF_LEAVE();
372 return VERR_INVALID_PARAMETER;
373 }
374
375 PHGSMIHOSTCOMMANDCONTEXT pCtx = &((PVBOXMP_COMMON)hHGSMI)->hostCtx;
376
377 /* pick up the host commands */
378 VBoxHGSMIProcessHostQueue(pCtx);
379
380 HGSMICHANNEL *pChannel = HGSMIChannelFindById(&pCtx->channels, u8Channel);
381 if(pChannel)
382 {
383 VBVA_CHANNELCONTEXTS * pContexts = (VBVA_CHANNELCONTEXTS *)pChannel->handler.pvHandler;
384 VBVADISP_CHANNELCONTEXT *pDispContext = VBoxVbvaFindHandlerInfo(pContexts, iDisplay);
385
386 if(pDispContext)
387 {
388 VBVAHOSTCMD *pCmd;
389 do
390 {
391 pCmd = ASMAtomicReadPtrT(&pDispContext->pCmd, VBVAHOSTCMD *);
392 } while (!ASMAtomicCmpXchgPtr(&pDispContext->pCmd, NULL, pCmd));
393 *ppCmd = VBoxVbvaReverseList(pCmd);
394
395 LOGF_LEAVE();
396 return VINF_SUCCESS;
397 }
398 else
399 {
400 WARN(("!pDispContext for display %d", iDisplay));
401 }
402 }
403
404 LOGF_LEAVE();
405 return VERR_INVALID_PARAMETER;
406}
407
408#define MEM_TAG 'HVBV'
409static void* VBoxMPMemAllocDriver(PVBOXMP_COMMON pCommon, const size_t size)
410{
411 ULONG Tag = MEM_TAG;
412 PVBOXMP_DEVEXT pExt = VBoxCommonToPrimaryExt(pCommon);
413 return pExt->u.primary.VideoPortProcs.pfnAllocatePool(pExt, (VBOXVP_POOL_TYPE)VpNonPagedPool, size, Tag);
414}
415
416static void VBoxMPMemFreeDriver(PVBOXMP_COMMON pCommon, void *pv)
417{
418 PVBOXMP_DEVEXT pExt = VBoxCommonToPrimaryExt(pCommon);
419 pExt->u.primary.VideoPortProcs.pfnFreePool(pExt, pv);
420}
421
422static int VBoxVbvaCreateChannelContexts(PVBOXMP_COMMON pCommon, VBVA_CHANNELCONTEXTS **ppContext)
423{
424 uint32_t cDisplays = (uint32_t)pCommon->cDisplays;
425 const size_t size = RT_OFFSETOF(VBVA_CHANNELCONTEXTS, aContexts[cDisplays]);
426 VBVA_CHANNELCONTEXTS *pContext = (VBVA_CHANNELCONTEXTS*) VBoxMPMemAllocDriver(pCommon, size);
427 if (pContext)
428 {
429 VideoPortZeroMemory(pContext, (ULONG)size);
430 pContext->cContexts = cDisplays;
431 pContext->pCommon = pCommon;
432 *ppContext = pContext;
433 return VINF_SUCCESS;
434 }
435
436 WARN(("Failed to allocate %d bytes", size));
437 return VERR_GENERAL_FAILURE;
438}
439
440static int VBoxVbvaDeleteChannelContexts(PVBOXMP_COMMON pCommon, VBVA_CHANNELCONTEXTS * pContext)
441{
442 VBoxMPMemFreeDriver(pCommon, pContext);
443 return VINF_SUCCESS;
444}
445
446static void VBoxMPSignalEvent(PVBOXMP_COMMON pCommon, uint64_t pvEvent)
447{
448 PVBOXMP_DEVEXT pExt = VBoxCommonToPrimaryExt(pCommon);
449 PEVENT pEvent = (PEVENT)pvEvent;
450 pExt->u.primary.VideoPortProcs.pfnSetEvent(pExt, pEvent);
451}
452
453static DECLCALLBACK(int)
454VBoxVbvaChannelGenericHandlerCB(void *pvHandler, uint16_t u16ChannelInfo, void *pvBuffer, HGSMISIZE cbBuffer)
455{
456 VBVA_CHANNELCONTEXTS *pCallbacks = (VBVA_CHANNELCONTEXTS*)pvHandler;
457 LOGF_ENTER();
458
459 Assert(cbBuffer > VBVAHOSTCMD_HDRSIZE);
460
461 if (cbBuffer > VBVAHOSTCMD_HDRSIZE)
462 {
463 VBVAHOSTCMD *pHdr = (VBVAHOSTCMD*)pvBuffer;
464 Assert(pHdr->iDstID >= 0);
465
466 if(pHdr->iDstID >= 0)
467 {
468 VBVADISP_CHANNELCONTEXT* pHandler = VBoxVbvaFindHandlerInfo(pCallbacks, pHdr->iDstID);
469 Assert(pHandler && pHandler->bValid);
470
471 if(pHandler && pHandler->bValid)
472 {
473 VBVAHOSTCMD *pFirst=NULL, *pLast=NULL, *pCur=pHdr;
474
475 while (pCur)
476 {
477 /*@todo: */
478 Assert(!pCur->u.Data);
479 Assert(!pFirst);
480 Assert(!pLast);
481
482 switch (u16ChannelInfo)
483 {
484 case VBVAHG_DISPLAY_CUSTOM:
485 {
486#if 0 /* Never taken */
487 if(pLast)
488 {
489 pLast->u.pNext = pCur;
490 pLast = pCur;
491 }
492 else
493#endif
494 {
495 pFirst = pCur;
496 pLast = pCur;
497 }
498 Assert(!pCur->u.Data);
499#if 0 /* Who is supposed to set pNext? */
500 //TODO: use offset here
501 pCur = pCur->u.pNext;
502 Assert(!pCur);
503#else
504 Assert(!pCur->u.pNext);
505 pCur = NULL;
506#endif
507 Assert(pFirst);
508 Assert(pFirst == pLast);
509 break;
510 }
511 case VBVAHG_EVENT:
512 {
513 VBVAHOSTCMDEVENT *pEventCmd = VBVAHOSTCMD_BODY(pCur, VBVAHOSTCMDEVENT);
514 VBoxMPSignalEvent(pCallbacks->pCommon, pEventCmd->pEvent);
515 }
516 default:
517 {
518 Assert(u16ChannelInfo==VBVAHG_EVENT);
519 Assert(!pCur->u.Data);
520#if 0 /* pLast has been asserted to be NULL, and who should set pNext? */
521 //TODO: use offset here
522 if(pLast)
523 pLast->u.pNext = pCur->u.pNext;
524 VBVAHOSTCMD * pNext = pCur->u.pNext;
525 pCur->u.pNext = NULL;
526#else
527 Assert(!pCur->u.pNext);
528#endif
529 VBoxHGSMIHostCmdComplete(&pCallbacks->pCommon->hostCtx, pCur);
530#if 0 /* pNext is NULL, and the other things have already been asserted */
531 pCur = pNext;
532 Assert(!pCur);
533 Assert(!pFirst);
534 Assert(pFirst == pLast);
535#else
536 pCur = NULL;
537#endif
538 }
539 }
540 }
541
542 /* we do not support lists currently */
543 Assert(pFirst == pLast);
544 if(pLast)
545 {
546 Assert(pLast->u.pNext == NULL);
547 }
548 if(pFirst)
549 {
550 Assert(pLast);
551 VBVAHOSTCMD *pCmd;
552 do
553 {
554 pCmd = ASMAtomicReadPtrT(&pHandler->pCmd, VBVAHOSTCMD *);
555 pFirst->u.pNext = pCmd;
556 }
557 while (!ASMAtomicCmpXchgPtr(&pHandler->pCmd, pFirst, pCmd));
558 }
559 else
560 {
561 Assert(!pLast);
562 }
563 LOGF_LEAVE();
564 return VINF_SUCCESS;
565 }
566 }
567 else
568 {
569 /*@todo*/
570 }
571 }
572
573 LOGF_LEAVE();
574
575 /* no handlers were found, need to complete the command here */
576 VBoxHGSMIHostCmdComplete(&pCallbacks->pCommon->hostCtx, pvBuffer);
577 return VINF_SUCCESS;
578}
579
580/* Note: negative iDisplay would mean this is a miniport handler */
581int VBoxVbvaChannelDisplayEnable(PVBOXMP_COMMON pCommon, int iDisplay, uint8_t u8Channel)
582{
583 static HGSMICHANNELHANDLER s_OldHandler;
584
585 LOGF_ENTER();
586
587 VBVA_CHANNELCONTEXTS * pContexts;
588 HGSMICHANNEL * pChannel = HGSMIChannelFindById(&pCommon->hostCtx.channels, u8Channel);
589
590 if (!pChannel)
591 {
592 int rc = VBoxVbvaCreateChannelContexts(pCommon, &pContexts);
593 if (RT_FAILURE(rc))
594 {
595 WARN(("VBoxVbvaCreateChannelContexts failed with rc=%#x", rc));
596 LOGF_LEAVE();
597 return rc;
598 }
599 }
600 else
601 {
602 pContexts = (VBVA_CHANNELCONTEXTS *)pChannel->handler.pvHandler;
603 }
604
605 VBVADISP_CHANNELCONTEXT *pDispContext = VBoxVbvaFindHandlerInfo(pContexts, iDisplay);
606 if (!pDispContext)
607 {
608 WARN(("!pDispContext"));
609 LOGF_LEAVE();
610 return VERR_GENERAL_FAILURE;
611 }
612
613#ifdef DEBUGVHWASTRICT
614 Assert(!pDispContext->bValid);
615#endif
616 Assert(!pDispContext->pCmd);
617
618 if (!pDispContext->bValid)
619 {
620 pDispContext->bValid = true;
621 pDispContext->pCmd = NULL;
622
623 int rc = VINF_SUCCESS;
624 if (!pChannel)
625 {
626 rc = HGSMIChannelRegister(&pCommon->hostCtx.channels, u8Channel,
627 "VGA Miniport HGSMI channel", VBoxVbvaChannelGenericHandlerCB,
628 pContexts, &s_OldHandler);
629 }
630
631 if (RT_SUCCESS(rc))
632 {
633 pContexts->cUsed++;
634 LOGF_LEAVE();
635 return VINF_SUCCESS;
636 }
637 else
638 {
639 WARN(("HGSMIChannelRegister failed with rc=%#x", rc));
640 }
641 }
642
643 if(!pChannel)
644 {
645 VBoxVbvaDeleteChannelContexts(pCommon, pContexts);
646 }
647
648 LOGF_LEAVE();
649 return VERR_GENERAL_FAILURE;
650}
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