VirtualBox

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

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use