VirtualBox

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

Last change on this file since 76563 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.4 KB
Line 
1/* $Id: VBoxMPInternal.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * VBox XPDM Miniport internal functions
4 */
5
6/*
7 * Copyright (C) 2011-2019 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#include "VBoxMPInternal.h"
19#include <VBoxVideo.h>
20#include <VBox/VBoxGuestLib.h>
21#include <iprt/asm.h>
22
23typedef struct _VBVAMINIPORT_CHANNELCONTEXT
24{
25 PFNHGSMICHANNELHANDLER pfnChannelHandler;
26 void *pvChannelHandler;
27} VBVAMINIPORT_CHANNELCONTEXT;
28
29typedef struct _VBVADISP_CHANNELCONTEXT
30{
31 /** The generic command handler builds up a list of commands - in reverse
32 * order! - here */
33 VBVAHOSTCMD *pCmd;
34 bool bValid;
35} VBVADISP_CHANNELCONTEXT;
36
37typedef struct _VBVA_CHANNELCONTEXTS
38{
39 PVBOXMP_COMMON pCommon;
40 uint32_t cUsed;
41 uint32_t cContexts;
42 VBVAMINIPORT_CHANNELCONTEXT mpContext;
43 VBVADISP_CHANNELCONTEXT aContexts[1];
44} VBVA_CHANNELCONTEXTS;
45
46/* Computes the size of a framebuffer. DualView has a few framebuffers of the computed size. */
47static void VBoxComputeFrameBufferSizes(PVBOXMP_DEVEXT pPrimaryExt)
48{
49 PVBOXMP_COMMON pCommon = VBoxCommonFromDeviceExt(pPrimaryExt);
50
51 ULONG ulAvailable = pCommon->cbVRAM - pCommon->cbMiniportHeap - VBVA_ADAPTER_INFORMATION_SIZE;
52 /* Size of a framebuffer. */
53 ULONG ulSize = ulAvailable / pCommon->cDisplays;
54 /* Align down to 4096 bytes. */
55 ulSize &= ~0xFFF;
56
57 LOG(("cbVRAM = 0x%08X, cDisplays = %d, ulSize = 0x%08X, ulSize * cDisplays = 0x%08X, slack = 0x%08X",
58 pCommon->cbVRAM, pCommon->cDisplays,
59 ulSize, ulSize * pCommon->cDisplays,
60 ulAvailable - ulSize * pCommon->cDisplays));
61
62 /* Update the primary info. */
63 pPrimaryExt->u.primary.ulMaxFrameBufferSize = ulSize;
64
65 /* Update the per extension info. */
66 PVBOXMP_DEVEXT pExt = pPrimaryExt;
67 ULONG ulFrameBufferOffset = 0;
68 while (pExt)
69 {
70 pExt->ulFrameBufferOffset = ulFrameBufferOffset;
71 /* That is assigned when a video mode is set. */
72 pExt->ulFrameBufferSize = 0;
73
74 LOG(("[%d] ulFrameBufferOffset 0x%08X", pExt->iDevice, ulFrameBufferOffset));
75
76 ulFrameBufferOffset += pPrimaryExt->u.primary.ulMaxFrameBufferSize;
77
78 pExt = pExt->pNext;
79 }
80}
81
82static DECLCALLBACK(int) VBoxVbvaInitInfoDisplayCB(void *pvData, struct VBVAINFOVIEW *p, uint32_t cViews)
83{
84 PVBOXMP_DEVEXT pExt, pPrimaryExt = (PVBOXMP_DEVEXT) pvData;
85 unsigned i;
86
87 for (i = 0, pExt=pPrimaryExt; i < cViews && pExt; i++, pExt = pExt->pNext)
88 {
89 p[i].u32ViewIndex = pExt->iDevice;
90 p[i].u32ViewOffset = pExt->ulFrameBufferOffset;
91 p[i].u32ViewSize = pPrimaryExt->u.primary.ulMaxFrameBufferSize;
92
93 /* How much VRAM should be reserved for the guest drivers to use VBVA. */
94 const uint32_t cbReservedVRAM = VBVA_DISPLAY_INFORMATION_SIZE + VBVA_MIN_BUFFER_SIZE;
95
96 p[i].u32MaxScreenSize = p[i].u32ViewSize > cbReservedVRAM?
97 p[i].u32ViewSize - cbReservedVRAM:
98 0;
99 }
100
101 if (i == (unsigned)VBoxCommonFromDeviceExt(pPrimaryExt)->cDisplays && pExt == NULL)
102 {
103 return VINF_SUCCESS;
104 }
105
106 AssertFailed ();
107 return VERR_INTERNAL_ERROR;
108}
109
110void VBoxCreateDisplays(PVBOXMP_DEVEXT pExt, PVIDEO_PORT_CONFIG_INFO pConfigInfo)
111{
112 RT_NOREF(pConfigInfo);
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 = VbglR0GRPerform (&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 = VbglR0QueryVMMDevMemory(&pVMMDevMemory);
222 if (RT_FAILURE(rc))
223 {
224 WARN(("VbglR0QueryVMMDevMemory 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 = VbglR0GRAlloc((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(("VbglR0GRAlloc(VMMDevVideoAccelFlush) rc = %#xrc", rc));
263 LOGF_LEAVE();
264 return rc;
265 }
266 }
267
268 ULONG ulEnabled = 0;
269
270 VMMDevVideoAccelEnable *req = NULL;
271 rc = VbglR0GRAlloc((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 = VbglR0GRPerform(&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 VbglR0GRPerform(&req->header);
309
310 rc = VERR_NOT_SUPPORTED;
311 }
312 }
313 else
314 {
315 WARN(("rc = %#xrc", rc));
316 }
317
318 VbglR0GRFree(&req->header);
319 }
320 else
321 {
322 WARN(("VbglR0GRAlloc(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
358/** @callback_method_impl{FNVBOXVIDEOHGSMICOMPLETION} */
359DECLCALLBACK(void) VBoxMPHGSMIHostCmdCompleteCB(HVBOXVIDEOHGSMI hHGSMI, struct VBVAHOSTCMD RT_UNTRUSTED_VOLATILE_HOST *pCmd)
360{
361 PHGSMIHOSTCOMMANDCONTEXT pCtx = &((PVBOXMP_COMMON)hHGSMI)->hostCtx;
362 VBoxHGSMIHostCmdComplete(pCtx, pCmd);
363}
364
365/** @callback_method_impl{FNVBOXVIDEOHGSMICOMMANDS} */
366DECLCALLBACK(int) VBoxMPHGSMIHostCmdRequestCB(HVBOXVIDEOHGSMI hHGSMI, uint8_t u8Channel,
367 uint32_t iDisplay, struct VBVAHOSTCMD RT_UNTRUSTED_VOLATILE_HOST **ppCmd)
368{
369 LOGF_ENTER();
370
371 if (!ppCmd)
372 {
373 LOGF_LEAVE();
374 return VERR_INVALID_PARAMETER;
375 }
376
377 PHGSMIHOSTCOMMANDCONTEXT pCtx = &((PVBOXMP_COMMON)hHGSMI)->hostCtx;
378
379 /* pick up the host commands */
380 VBoxHGSMIProcessHostQueue(pCtx);
381
382 HGSMICHANNEL *pChannel = HGSMIChannelFindById(&pCtx->channels, u8Channel);
383 if (pChannel)
384 {
385 VBVA_CHANNELCONTEXTS * pContexts = (VBVA_CHANNELCONTEXTS *)pChannel->handler.pvHandler;
386 VBVADISP_CHANNELCONTEXT *pDispContext = VBoxVbvaFindHandlerInfo(pContexts, iDisplay);
387
388 if (pDispContext)
389 {
390 VBVAHOSTCMD *pCmd;
391 do
392 {
393 pCmd = ASMAtomicReadPtrT(&pDispContext->pCmd, VBVAHOSTCMD *);
394 } while (!ASMAtomicCmpXchgPtr(&pDispContext->pCmd, NULL, pCmd));
395
396 *ppCmd = VBoxVbvaReverseList(pCmd);
397
398 LOGF_LEAVE();
399 return VINF_SUCCESS;
400 }
401 WARN(("!pDispContext for display %d", iDisplay));
402 }
403
404 *ppCmd = NULL;
405 LOGF_LEAVE();
406 return VERR_INVALID_PARAMETER;
407}
408
409#define MEM_TAG 'HVBV'
410static void* VBoxMPMemAllocDriver(PVBOXMP_COMMON pCommon, const size_t size)
411{
412 ULONG Tag = MEM_TAG;
413 PVBOXMP_DEVEXT pExt = VBoxCommonToPrimaryExt(pCommon);
414 return pExt->u.primary.VideoPortProcs.pfnAllocatePool(pExt, (VBOXVP_POOL_TYPE)VpNonPagedPool, size, Tag);
415}
416
417static void VBoxMPMemFreeDriver(PVBOXMP_COMMON pCommon, void *pv)
418{
419 PVBOXMP_DEVEXT pExt = VBoxCommonToPrimaryExt(pCommon);
420 pExt->u.primary.VideoPortProcs.pfnFreePool(pExt, pv);
421}
422
423static int VBoxVbvaCreateChannelContexts(PVBOXMP_COMMON pCommon, VBVA_CHANNELCONTEXTS **ppContext)
424{
425 uint32_t cDisplays = (uint32_t)pCommon->cDisplays;
426 const size_t size = RT_UOFFSETOF_DYN(VBVA_CHANNELCONTEXTS, aContexts[cDisplays]);
427 VBVA_CHANNELCONTEXTS *pContext = (VBVA_CHANNELCONTEXTS*) VBoxMPMemAllocDriver(pCommon, size);
428 if (pContext)
429 {
430 VideoPortZeroMemory(pContext, (ULONG)size);
431 pContext->cContexts = cDisplays;
432 pContext->pCommon = pCommon;
433 *ppContext = pContext;
434 return VINF_SUCCESS;
435 }
436
437 WARN(("Failed to allocate %d bytes", size));
438 return VERR_GENERAL_FAILURE;
439}
440
441static int VBoxVbvaDeleteChannelContexts(PVBOXMP_COMMON pCommon, VBVA_CHANNELCONTEXTS * pContext)
442{
443 VBoxMPMemFreeDriver(pCommon, pContext);
444 return VINF_SUCCESS;
445}
446
447static void VBoxMPSignalEvent(PVBOXMP_COMMON pCommon, uint64_t pvEvent)
448{
449 PVBOXMP_DEVEXT pExt = VBoxCommonToPrimaryExt(pCommon);
450 PEVENT pEvent = (PEVENT)pvEvent;
451 pExt->u.primary.VideoPortProcs.pfnSetEvent(pExt, pEvent);
452}
453
454static DECLCALLBACK(int)
455VBoxVbvaChannelGenericHandlerCB(void *pvHandler, uint16_t u16ChannelInfo,
456 void RT_UNTRUSTED_VOLATILE_HOST *pvBuffer, HGSMISIZE cbBuffer)
457{
458 VBVA_CHANNELCONTEXTS *pCallbacks = (VBVA_CHANNELCONTEXTS*)pvHandler;
459 LOGF_ENTER();
460
461 Assert(cbBuffer > VBVAHOSTCMD_HDRSIZE);
462
463 if (cbBuffer > VBVAHOSTCMD_HDRSIZE)
464 {
465 VBVAHOSTCMD *pHdr = (VBVAHOSTCMD*)pvBuffer;
466 Assert(pHdr->iDstID >= 0);
467
468 if(pHdr->iDstID >= 0)
469 {
470 VBVADISP_CHANNELCONTEXT* pHandler = VBoxVbvaFindHandlerInfo(pCallbacks, pHdr->iDstID);
471 Assert(pHandler && pHandler->bValid);
472
473 if(pHandler && pHandler->bValid)
474 {
475 VBVAHOSTCMD *pFirst=NULL, *pLast=NULL, *pCur=pHdr;
476
477 while (pCur)
478 {
479 /** @todo */
480 Assert(!pCur->u.Data);
481 Assert(!pFirst);
482 Assert(!pLast);
483
484 switch (u16ChannelInfo)
485 {
486 case VBVAHG_DISPLAY_CUSTOM:
487 {
488#if 0 /* Never taken */
489 if(pLast)
490 {
491 pLast->u.pNext = pCur;
492 pLast = pCur;
493 }
494 else
495#endif
496 {
497 pFirst = pCur;
498 pLast = pCur;
499 }
500 Assert(!pCur->u.Data);
501#if 0 /* Who is supposed to set pNext? */
502 /// @todo use offset here
503 pCur = pCur->u.pNext;
504 Assert(!pCur);
505#else
506 Assert(!pCur->u.pNext);
507 pCur = NULL;
508#endif
509 Assert(pFirst);
510 Assert(pFirst == pLast);
511 break;
512 }
513
514 case VBVAHG_EVENT:
515 {
516 VBVAHOSTCMDEVENT RT_UNTRUSTED_VOLATILE_HOST *pEventCmd = VBVAHOSTCMD_BODY(pCur, VBVAHOSTCMDEVENT);
517 VBoxMPSignalEvent(pCallbacks->pCommon, pEventCmd->pEvent);
518 }
519
520 default:
521 {
522 Assert(u16ChannelInfo==VBVAHG_EVENT);
523 Assert(!pCur->u.Data);
524#if 0 /* pLast has been asserted to be NULL, and who should set pNext? */
525 /// @todo use offset here
526 if(pLast)
527 pLast->u.pNext = pCur->u.pNext;
528 VBVAHOSTCMD * pNext = pCur->u.pNext;
529 pCur->u.pNext = NULL;
530#else
531 Assert(!pCur->u.pNext);
532#endif
533 VBoxHGSMIHostCmdComplete(&pCallbacks->pCommon->hostCtx, pCur);
534#if 0 /* pNext is NULL, and the other things have already been asserted */
535 pCur = pNext;
536 Assert(!pCur);
537 Assert(!pFirst);
538 Assert(pFirst == pLast);
539#else
540 pCur = NULL;
541#endif
542 }
543 }
544 }
545
546 /* we do not support lists currently */
547 Assert(pFirst == pLast);
548 if(pLast)
549 {
550 Assert(pLast->u.pNext == NULL);
551 }
552 if(pFirst)
553 {
554 Assert(pLast);
555 VBVAHOSTCMD *pCmd;
556 do
557 {
558 pCmd = ASMAtomicReadPtrT(&pHandler->pCmd, VBVAHOSTCMD *);
559 pFirst->u.pNext = pCmd;
560 }
561 while (!ASMAtomicCmpXchgPtr(&pHandler->pCmd, pFirst, pCmd));
562 }
563 else
564 {
565 Assert(!pLast);
566 }
567 LOGF_LEAVE();
568 return VINF_SUCCESS;
569 }
570 }
571 else
572 {
573 /** @todo */
574 }
575 }
576
577 LOGF_LEAVE();
578
579 /* no handlers were found, need to complete the command here */
580 VBoxHGSMIHostCmdComplete(&pCallbacks->pCommon->hostCtx, pvBuffer);
581 return VINF_SUCCESS;
582}
583
584/* Note: negative iDisplay would mean this is a miniport handler */
585int VBoxVbvaChannelDisplayEnable(PVBOXMP_COMMON pCommon, int iDisplay, uint8_t u8Channel)
586{
587 LOGF_ENTER();
588
589 VBVA_CHANNELCONTEXTS * pContexts;
590 HGSMICHANNEL * pChannel = HGSMIChannelFindById(&pCommon->hostCtx.channels, u8Channel);
591
592 if (!pChannel)
593 {
594 int rc = VBoxVbvaCreateChannelContexts(pCommon, &pContexts);
595 if (RT_FAILURE(rc))
596 {
597 WARN(("VBoxVbvaCreateChannelContexts failed with rc=%#x", rc));
598 LOGF_LEAVE();
599 return rc;
600 }
601 }
602 else
603 {
604 pContexts = (VBVA_CHANNELCONTEXTS *)pChannel->handler.pvHandler;
605 }
606
607 VBVADISP_CHANNELCONTEXT *pDispContext = VBoxVbvaFindHandlerInfo(pContexts, iDisplay);
608 if (!pDispContext)
609 {
610 WARN(("!pDispContext"));
611 LOGF_LEAVE();
612 return VERR_GENERAL_FAILURE;
613 }
614
615#ifdef DEBUGVHWASTRICT
616 Assert(!pDispContext->bValid);
617#endif
618 Assert(!pDispContext->pCmd);
619
620 if (!pDispContext->bValid)
621 {
622 pDispContext->bValid = true;
623 pDispContext->pCmd = NULL;
624
625 int rc = VINF_SUCCESS;
626 if (!pChannel)
627 {
628 rc = HGSMIChannelRegister(&pCommon->hostCtx.channels, u8Channel,
629 "VGA Miniport HGSMI channel", VBoxVbvaChannelGenericHandlerCB,
630 pContexts);
631 }
632
633 if (RT_SUCCESS(rc))
634 {
635 pContexts->cUsed++;
636 LOGF_LEAVE();
637 return VINF_SUCCESS;
638 }
639 else
640 {
641 WARN(("HGSMIChannelRegister failed with rc=%#x", rc));
642 }
643 }
644
645 if(!pChannel)
646 {
647 VBoxVbvaDeleteChannelContexts(pCommon, pContexts);
648 }
649
650 LOGF_LEAVE();
651 return VERR_GENERAL_FAILURE;
652}
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