VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Miniport/VBoxVideoHGSMI.cpp@ 33280

Last change on this file since 33280 was 33252, checked in by vboxsync, 14 years ago

Additions/WINNT/Graphics: more refactoring and some re-ordering

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 55.8 KB
Line 
1/* $Id: VBoxVideoHGSMI.cpp 33252 2010-10-20 10:25:22Z vboxsync $ */
2/** @file
3 * VirtualBox Video miniport driver for NT/2k/XP - HGSMI related functions.
4 */
5
6/*
7 * Copyright (C) 2006-2009 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
19#include "VBoxVideo.h"
20#include "Helper.h"
21
22#include <iprt/asm.h>
23#include <iprt/log.h>
24#include <iprt/thread.h>
25#include <VBox/VMMDev.h>
26#include <VBox/VBoxGuest.h>
27#include <VBox/VBoxVideo.h>
28
29#include <VBoxDisplay.h>
30
31#include "vboxioctl.h"
32
33#define MEM_TAG 'HVBV'
34
35void HGSMINotifyHostCmdComplete (PVBOXVIDEO_COMMON pCommon, HGSMIOFFSET offt)
36{
37 VBoxHGSMIHostWrite(pCommon, offt);
38}
39
40void HGSMIClearIrq (PVBOXVIDEO_COMMON pCommon)
41{
42 VBoxHGSMIHostWrite(pCommon, HGSMIOFFSET_VOID);
43}
44
45static void HGSMIHostCmdComplete (PVBOXVIDEO_COMMON pCommon, void * pvMem)
46{
47 HGSMIOFFSET offMem = HGSMIPointerToOffset (&pCommon->areaHostHeap, HGSMIBufferHeaderFromData (pvMem));
48 Assert(offMem != HGSMIOFFSET_VOID);
49 if(offMem != HGSMIOFFSET_VOID)
50 {
51 HGSMINotifyHostCmdComplete (pCommon, offMem);
52 }
53}
54
55static void hgsmiHostCmdProcess(PVBOXVIDEO_COMMON pCommon, HGSMIOFFSET offBuffer)
56{
57 int rc = HGSMIBufferProcess (&pCommon->areaHostHeap,
58 &pCommon->channels,
59 offBuffer);
60 Assert(!RT_FAILURE(rc));
61 if(RT_FAILURE(rc))
62 {
63 /* failure means the command was not submitted to the handler for some reason
64 * it's our responsibility to notify its completion in this case */
65 HGSMINotifyHostCmdComplete(pCommon, offBuffer);
66 }
67 /* if the cmd succeeded it's responsibility of the callback to complete it */
68}
69
70static HGSMIOFFSET hgsmiGetHostBuffer (PVBOXVIDEO_COMMON pCommon)
71{
72 return VBoxHGSMIHostRead(pCommon);
73}
74
75static void hgsmiHostCommandQueryProcess (PVBOXVIDEO_COMMON pCommon)
76{
77 HGSMIOFFSET offset = hgsmiGetHostBuffer (pCommon);
78 Assert(offset != HGSMIOFFSET_VOID);
79 if(offset != HGSMIOFFSET_VOID)
80 {
81 hgsmiHostCmdProcess(pCommon, offset);
82 }
83}
84
85#define VBOX_HGSMI_LOCK(_pe, _plock, _dpc, _pold) \
86 do { \
87 if(_dpc) \
88 { \
89 VBoxVideoCmnSpinLockAcquireAtDpcLevel(_pe, _plock); \
90 } \
91 else \
92 {\
93 VBoxVideoCmnSpinLockAcquire(_pe, _plock, _pold); \
94 }\
95 } while(0)
96
97#define VBOX_HGSMI_UNLOCK(_pe, _plock, _dpc, _pold) \
98 do { \
99 if(_dpc) \
100 { \
101 VBoxVideoCmnSpinLockReleaseFromDpcLevel(_pe, _plock); \
102 } \
103 else \
104 {\
105 VBoxVideoCmnSpinLockRelease(_pe, _plock, _pold); \
106 }\
107 } while(0)
108
109VOID VBoxVideoHGSMIDpc(
110 IN PVOID HwDeviceExtension,
111 IN PVOID Context
112 )
113{
114 PDEVICE_EXTENSION PrimaryExtension = (PDEVICE_EXTENSION)HwDeviceExtension;
115 uint32_t flags = (uint32_t)Context;
116 bool bProcessing = false;
117 VBOXVCMNIRQL OldIrql;
118 /* we check if another thread is processing the queue and exit if so */
119 do
120 {
121 bool bLock = false;
122 if(!(commonFromDeviceExt(PrimaryExtension)->pHostFlags->u32HostFlags & HGSMIHOSTFLAGS_COMMANDS_PENDING))
123 {
124 if(!bProcessing)
125 {
126 break;
127 }
128 VBOX_HGSMI_LOCK(PrimaryExtension, &PrimaryExtension->u.primary.pSynchLock, flags, &OldIrql);
129 if(!(commonFromDeviceExt(PrimaryExtension)->pHostFlags->u32HostFlags & HGSMIHOSTFLAGS_COMMANDS_PENDING))
130 {
131 Assert(commonFromDeviceExt(PrimaryExtension)->bHostCmdProcessing);
132 commonFromDeviceExt(PrimaryExtension)->bHostCmdProcessing = false;
133 VBOX_HGSMI_UNLOCK(PrimaryExtension, &PrimaryExtension->u.primary.pSynchLock, flags, OldIrql);
134 break;
135 }
136 VBOX_HGSMI_UNLOCK(PrimaryExtension, &PrimaryExtension->u.primary.pSynchLock, flags, OldIrql);
137 }
138 else
139 {
140 if(!bProcessing)
141 {
142 VBOX_HGSMI_LOCK(PrimaryExtension, &PrimaryExtension->u.primary.pSynchLock, flags, &OldIrql);
143 if(!(commonFromDeviceExt(PrimaryExtension)->pHostFlags->u32HostFlags & HGSMIHOSTFLAGS_COMMANDS_PENDING)
144 || commonFromDeviceExt(PrimaryExtension)->bHostCmdProcessing)
145 {
146 VBOX_HGSMI_UNLOCK(PrimaryExtension, &PrimaryExtension->u.primary.pSynchLock, flags, OldIrql);
147 break;
148 }
149 Assert(!commonFromDeviceExt(PrimaryExtension)->bHostCmdProcessing);
150 commonFromDeviceExt(PrimaryExtension)->bHostCmdProcessing = true;
151 VBOX_HGSMI_UNLOCK(PrimaryExtension, &PrimaryExtension->u.primary.pSynchLock, flags, OldIrql);
152 bProcessing = true;
153 }
154 }
155
156 Assert(bProcessing);
157 Assert(commonFromDeviceExt(PrimaryExtension)->bHostCmdProcessing);
158 Assert((commonFromDeviceExt(PrimaryExtension)->pHostFlags->u32HostFlags & HGSMIHOSTFLAGS_COMMANDS_PENDING) != 0);
159 bProcessing = true;
160
161 hgsmiHostCommandQueryProcess (commonFromDeviceExt(PrimaryExtension));
162 } while(true/*!PrimaryExtension->u.primary.bPollingStop*/);
163}
164
165/* Detect whether HGSMI is supported by the host. */
166BOOLEAN VBoxHGSMIIsSupported (void)
167{
168 USHORT DispiId;
169
170 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
171 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID_HGSMI);
172
173 DispiId = VBoxVideoCmnPortReadUshort((PUSHORT)VBE_DISPI_IOPORT_DATA);
174
175 return (DispiId == VBE_DISPI_ID_HGSMI);
176}
177
178typedef int FNHGSMICALLINIT (PVBOXVIDEO_COMMON pCommon, void *pvContext, void *pvData);
179typedef FNHGSMICALLINIT *PFNHGSMICALLINIT;
180
181typedef int FNHGSMICALLFINALIZE (PVBOXVIDEO_COMMON pCommon, void *pvContext, void *pvData);
182typedef FNHGSMICALLFINALIZE *PFNHGSMICALLFINALIZE;
183
184void* vboxHGSMIBufferAlloc(PVBOXVIDEO_COMMON pCommon,
185 HGSMISIZE cbData,
186 uint8_t u8Ch,
187 uint16_t u16Op)
188{
189#ifdef VBOX_WITH_WDDM
190 /* @todo: add synchronization */
191#endif
192 return HGSMIHeapAlloc (&pCommon->hgsmiAdapterHeap, cbData, u8Ch, u16Op);
193}
194
195void vboxHGSMIBufferFree (PVBOXVIDEO_COMMON pCommon, void *pvBuffer)
196{
197#ifdef VBOX_WITH_WDDM
198 /* @todo: add synchronization */
199#endif
200 HGSMIHeapFree (&pCommon->hgsmiAdapterHeap, pvBuffer);
201}
202
203int vboxHGSMIBufferSubmit (PVBOXVIDEO_COMMON pCommon, void *pvBuffer)
204{
205 /* Initialize the buffer and get the offset for port IO. */
206 HGSMIOFFSET offBuffer = HGSMIHeapBufferOffset (&pCommon->hgsmiAdapterHeap, pvBuffer);
207
208 Assert(offBuffer != HGSMIOFFSET_VOID);
209 if (offBuffer != HGSMIOFFSET_VOID)
210 {
211 /* Submit the buffer to the host. */
212 VBoxHGSMIGuestWrite(pCommon, offBuffer);
213 return VINF_SUCCESS;
214 }
215
216 return VERR_INVALID_PARAMETER;
217}
218
219static int vboxCallChannel (PVBOXVIDEO_COMMON pCommon,
220 uint8_t u8Ch,
221 uint16_t u16Op,
222 HGSMISIZE cbData,
223 PFNHGSMICALLINIT pfnInit,
224 PFNHGSMICALLFINALIZE pfnFinalize,
225 void *pvContext)
226{
227 int rc = VINF_SUCCESS;
228
229 /* Allocate the IO buffer. */
230 void *p = HGSMIHeapAlloc (&pCommon->hgsmiAdapterHeap, cbData, u8Ch, u16Op);
231
232 if (!p)
233 {
234 rc = VERR_NO_MEMORY;
235 }
236 else
237 {
238 /* Prepare data to be sent to the host. */
239 if (pfnInit)
240 {
241 rc = pfnInit (pCommon, pvContext, p);
242 }
243
244 if (RT_SUCCESS (rc))
245 {
246 /* Initialize the buffer and get the offset for port IO. */
247 HGSMIOFFSET offBuffer = HGSMIHeapBufferOffset (&pCommon->hgsmiAdapterHeap,
248 p);
249
250 /* Submit the buffer to the host. */
251 VBoxHGSMIGuestWrite(pCommon, offBuffer);
252
253 if (pfnFinalize)
254 {
255 rc = pfnFinalize (pCommon, pvContext, p);
256 }
257 }
258 else
259 {
260 AssertFailed ();
261 rc = VERR_INTERNAL_ERROR;
262 }
263
264 /* Free the IO buffer. */
265 HGSMIHeapFree (&pCommon->hgsmiAdapterHeap, p);
266 }
267
268 return rc;
269}
270
271static int vboxCallVBVA (PVBOXVIDEO_COMMON pCommon,
272 uint16_t u16Op,
273 HGSMISIZE cbData,
274 PFNHGSMICALLINIT pfnInit,
275 PFNHGSMICALLFINALIZE pfnFinalize,
276 void *pvContext)
277{
278 return vboxCallChannel (pCommon,
279 HGSMI_CH_VBVA,
280 u16Op,
281 cbData,
282 pfnInit,
283 pfnFinalize,
284 pvContext);
285}
286
287typedef struct _QUERYCONFCTX
288{
289 uint32_t u32Index;
290 ULONG *pulValue;
291} QUERYCONFCTX;
292
293static int vbvaInitQueryConf (PVBOXVIDEO_COMMON, void *pvContext, void *pvData)
294{
295 QUERYCONFCTX *pCtx = (QUERYCONFCTX *)pvContext;
296 VBVACONF32 *p = (VBVACONF32 *)pvData;
297
298 p->u32Index = pCtx->u32Index;
299 p->u32Value = 0;
300
301 return VINF_SUCCESS;
302}
303
304static int vbvaFinalizeQueryConf (PVBOXVIDEO_COMMON, void *pvContext, void *pvData)
305{
306 QUERYCONFCTX *pCtx = (QUERYCONFCTX *)pvContext;
307 VBVACONF32 *p = (VBVACONF32 *)pvData;
308
309 if (pCtx->pulValue)
310 {
311 *pCtx->pulValue = p->u32Value;
312 }
313
314 dprintf(("VBoxVideo::vboxQueryConf: u32Value = %d\n", p->u32Value));
315 return VINF_SUCCESS;
316}
317
318static int vboxQueryConfHGSMI (PVBOXVIDEO_COMMON pCommon, uint32_t u32Index, ULONG *pulValue)
319{
320 dprintf(("VBoxVideo::vboxQueryConf: u32Index = %d\n", u32Index));
321
322 QUERYCONFCTX context;
323
324 context.u32Index = u32Index;
325 context.pulValue = pulValue;
326
327 int rc = vboxCallVBVA (pCommon,
328 VBVA_QUERY_CONF32,
329 sizeof (VBVACONF32),
330 vbvaInitQueryConf,
331 vbvaFinalizeQueryConf,
332 &context);
333
334 dprintf(("VBoxVideo::vboxQueryConf: rc = %d\n", rc));
335
336 return rc;
337}
338
339int VBoxHGSMISendViewInfo(PVBOXVIDEO_COMMON pCommon, uint32_t u32Count, PFNHGSMIFILLVIEWINFO pfnFill, void *pvData)
340{
341 int rc;
342 /* Issue the screen info command. */
343 void *p = vboxHGSMIBufferAlloc (pCommon, sizeof(VBVAINFOVIEW) * u32Count,
344 HGSMI_CH_VBVA, VBVA_INFO_VIEW);
345 Assert(p);
346 if (p)
347 {
348 VBVAINFOVIEW *pInfo = (VBVAINFOVIEW *)p;
349 rc = pfnFill(pvData, pInfo);
350 if (RT_SUCCESS(rc))
351 vboxHGSMIBufferSubmit (pCommon, p);
352 vboxHGSMIBufferFree (pCommon, p);
353 }
354 else
355 rc = VERR_NO_MEMORY;
356 return rc;
357}
358
359#ifndef VBOX_WITH_WDDM
360static int vbvaInitInfoDisplay (void *pvData, VBVAINFOVIEW *p)
361{
362 PDEVICE_EXTENSION PrimaryExtension = (PDEVICE_EXTENSION) pvData;
363
364 int i;
365 PDEVICE_EXTENSION Extension;
366
367 for (i = 0, Extension = PrimaryExtension;
368 i < commonFromDeviceExt(PrimaryExtension)->cDisplays && Extension;
369 i++, Extension = Extension->pNext)
370 {
371 p[i].u32ViewIndex = Extension->iDevice;
372 p[i].u32ViewOffset = Extension->ulFrameBufferOffset;
373 p[i].u32ViewSize = PrimaryExtension->u.primary.ulMaxFrameBufferSize;
374
375 /* How much VRAM should be reserved for the guest drivers to use VBVA. */
376 const uint32_t cbReservedVRAM = VBVA_DISPLAY_INFORMATION_SIZE + VBVA_MIN_BUFFER_SIZE;
377
378 p[i].u32MaxScreenSize = p[i].u32ViewSize > cbReservedVRAM?
379 p[i].u32ViewSize - cbReservedVRAM:
380 0;
381 }
382
383 if (i == commonFromDeviceExt(PrimaryExtension)->cDisplays && Extension == NULL)
384 {
385 return VINF_SUCCESS;
386 }
387
388 AssertFailed ();
389 return VERR_INTERNAL_ERROR;
390}
391#endif
392int vbvaInitInfoCaps (PVBOXVIDEO_COMMON pCommon, void *pvContext, void *pvData)
393{
394 VBVACAPS *pCaps = (VBVACAPS*)pvData;
395 pCaps->rc = VERR_NOT_IMPLEMENTED;
396 pCaps->fCaps = pCommon->fCaps;
397 return VINF_SUCCESS;
398}
399
400
401int vbvaFinalizeInfoCaps (PVBOXVIDEO_COMMON, void *pvContext, void *pvData)
402{
403 VBVACAPS *pCaps = (VBVACAPS*)pvData;
404 AssertRC(pCaps->rc);
405 return pCaps->rc;
406}
407
408static int vbvaInitInfoHeap (PVBOXVIDEO_COMMON pCommon, void *pvContext, void *pvData)
409{
410 NOREF (pvContext);
411 VBVAINFOHEAP *p = (VBVAINFOHEAP *)pvData;
412
413 p->u32HeapOffset = pCommon->cbVRAM
414 - pCommon->cbMiniportHeap
415 - VBVA_ADAPTER_INFORMATION_SIZE;
416 p->u32HeapSize = pCommon->cbMiniportHeap;
417
418 return VINF_SUCCESS;
419}
420
421static int hgsmiInitFlagsLocation (PVBOXVIDEO_COMMON pCommon, void *pvContext, void *pvData)
422{
423 NOREF (pvContext);
424 HGSMIBUFFERLOCATION *p = (HGSMIBUFFERLOCATION *)pvData;
425
426 p->offLocation = pCommon->cbVRAM - sizeof (HGSMIHOSTFLAGS);
427 p->cbLocation = sizeof (HGSMIHOSTFLAGS);
428
429 return VINF_SUCCESS;
430}
431
432
433static int vboxSetupAdapterInfoHGSMI (PVBOXVIDEO_COMMON pCommon)
434{
435 dprintf(("VBoxVideo::vboxSetupAdapterInfo\n"));
436
437 /* setup the flags first to ensure they are initialized by the time the host heap is ready */
438 int rc = vboxCallChannel(pCommon,
439 HGSMI_CH_HGSMI,
440 HGSMI_CC_HOST_FLAGS_LOCATION,
441 sizeof (HGSMIBUFFERLOCATION),
442 hgsmiInitFlagsLocation,
443 NULL,
444 NULL);
445 AssertRC(rc);
446 if (RT_SUCCESS(rc) && pCommon->fCaps)
447 {
448 /* Inform about caps */
449 rc = vboxCallVBVA (pCommon,
450 VBVA_INFO_CAPS,
451 sizeof (VBVACAPS),
452 vbvaInitInfoCaps,
453 vbvaFinalizeInfoCaps,
454 NULL);
455 AssertRC(rc);
456 }
457 if (RT_SUCCESS (rc))
458 {
459 /* Report the host heap location. */
460 rc = vboxCallVBVA (pCommon,
461 VBVA_INFO_HEAP,
462 sizeof (VBVAINFOHEAP),
463 vbvaInitInfoHeap,
464 NULL,
465 NULL);
466 AssertRC(rc);
467 }
468
469
470 dprintf(("VBoxVideo::vboxSetupAdapterInfo finished rc = %d\n", rc));
471
472 return rc;
473}
474
475#ifndef VBOX_WITH_WDDM
476VP_STATUS vboxWaitForSingleObjectVoid(IN PVOID HwDeviceExtension, IN PVOID Object, IN PLARGE_INTEGER Timeout OPTIONAL)
477{
478 return ERROR_INVALID_FUNCTION;
479}
480
481LONG vboxSetEventVoid(IN PVOID HwDeviceExtension, IN PEVENT pEvent)
482{
483 return 0;
484}
485
486VOID vboxClearEventVoid (IN PVOID HwDeviceExtension, IN PEVENT pEvent)
487{
488}
489
490VP_STATUS vboxCreateEventVoid(IN PVOID HwDeviceExtension, IN ULONG EventFlag, IN PVOID Unused, OUT PEVENT *ppEvent)
491{
492 return ERROR_INVALID_FUNCTION;
493}
494
495VP_STATUS vboxDeleteEventVoid(IN PVOID HwDeviceExtension, IN PEVENT pEvent)
496{
497 return ERROR_INVALID_FUNCTION;
498}
499
500VP_STATUS vboxCreateSpinLockVoid (IN PVOID HwDeviceExtension, OUT PSPIN_LOCK *SpinLock)
501{
502 return ERROR_INVALID_FUNCTION;
503}
504
505VP_STATUS vboxDeleteSpinLockVoid (IN PVOID HwDeviceExtension, IN PSPIN_LOCK SpinLock)
506{
507 return ERROR_INVALID_FUNCTION;
508}
509
510VOID vboxAcquireSpinLockVoid (IN PVOID HwDeviceExtension, IN PSPIN_LOCK SpinLock, OUT PUCHAR OldIrql)
511{
512}
513
514VOID vboxReleaseSpinLockVoid (IN PVOID HwDeviceExtension, IN PSPIN_LOCK SpinLock, IN UCHAR NewIrql)
515{
516}
517
518VOID vboxAcquireSpinLockAtDpcLevelVoid (IN PVOID HwDeviceExtension, IN PSPIN_LOCK SpinLock)
519{
520}
521
522VOID vboxReleaseSpinLockFromDpcLevelVoid (IN PVOID HwDeviceExtension, IN PSPIN_LOCK SpinLock)
523{
524}
525
526PVOID vboxAllocatePoolVoid(IN PVOID HwDeviceExtension, IN VBOXVP_POOL_TYPE PoolType, IN size_t NumberOfBytes, IN ULONG Tag)
527{
528 return NULL;
529}
530
531VOID vboxFreePoolVoid(IN PVOID HwDeviceExtension, IN PVOID Ptr)
532{
533}
534
535BOOLEAN vboxQueueDpcVoid(IN PVOID HwDeviceExtension, IN PMINIPORT_DPC_ROUTINE CallbackRoutine, IN PVOID Context)
536{
537 return FALSE;
538}
539
540void VBoxSetupVideoPortFunctions(PDEVICE_EXTENSION PrimaryExtension, VBOXVIDEOPORTPROCS *pCallbacks, PVIDEO_PORT_CONFIG_INFO pConfigInfo)
541{
542 memset(pCallbacks, 0, sizeof(VBOXVIDEOPORTPROCS));
543
544 if (vboxQueryWinVersion() <= WINNT4)
545 {
546 /* VideoPortGetProcAddress is available for >= win2k */
547 pCallbacks->pfnWaitForSingleObject = vboxWaitForSingleObjectVoid;
548 pCallbacks->pfnSetEvent = vboxSetEventVoid;
549 pCallbacks->pfnClearEvent = vboxClearEventVoid;
550 pCallbacks->pfnCreateEvent = vboxCreateEventVoid;
551 pCallbacks->pfnDeleteEvent = vboxDeleteEventVoid;
552 pCallbacks->pfnCreateSpinLock = vboxCreateSpinLockVoid;
553 pCallbacks->pfnDeleteSpinLock = vboxDeleteSpinLockVoid;
554 pCallbacks->pfnAcquireSpinLock = vboxAcquireSpinLockVoid;
555 pCallbacks->pfnReleaseSpinLock = vboxReleaseSpinLockVoid;
556 pCallbacks->pfnAcquireSpinLockAtDpcLevel = vboxAcquireSpinLockAtDpcLevelVoid;
557 pCallbacks->pfnReleaseSpinLockFromDpcLevel = vboxReleaseSpinLockFromDpcLevelVoid;
558 pCallbacks->pfnAllocatePool = vboxAllocatePoolVoid;
559 pCallbacks->pfnFreePool = vboxFreePoolVoid;
560 pCallbacks->pfnQueueDpc = vboxQueueDpcVoid;
561 return;
562 }
563
564 pCallbacks->pfnWaitForSingleObject = (PFNWAITFORSINGLEOBJECT)(pConfigInfo->VideoPortGetProcAddress)
565 (PrimaryExtension,
566 (PUCHAR)"VideoPortWaitForSingleObject");
567 Assert(pCallbacks->pfnWaitForSingleObject);
568
569 pCallbacks->pfnSetEvent = (PFNSETEVENT)(pConfigInfo->VideoPortGetProcAddress)
570 (PrimaryExtension,
571 (PUCHAR)"VideoPortSetEvent");
572 Assert(pCallbacks->pfnSetEvent);
573
574 pCallbacks->pfnClearEvent = (PFNCLEAREVENT)(pConfigInfo->VideoPortGetProcAddress)
575 (PrimaryExtension,
576 (PUCHAR)"VideoPortClearEvent");
577 Assert(pCallbacks->pfnClearEvent);
578
579 pCallbacks->pfnCreateEvent = (PFNCREATEEVENT)(pConfigInfo->VideoPortGetProcAddress)
580 (PrimaryExtension,
581 (PUCHAR)"VideoPortCreateEvent");
582 Assert(pCallbacks->pfnCreateEvent);
583
584 pCallbacks->pfnDeleteEvent = (PFNDELETEEVENT)(pConfigInfo->VideoPortGetProcAddress)
585 (PrimaryExtension,
586 (PUCHAR)"VideoPortDeleteEvent");
587 Assert(pCallbacks->pfnDeleteEvent);
588
589 if(pCallbacks->pfnWaitForSingleObject
590 && pCallbacks->pfnSetEvent
591 && pCallbacks->pfnClearEvent
592 && pCallbacks->pfnCreateEvent
593 && pCallbacks->pfnDeleteEvent)
594 {
595 pCallbacks->fSupportedTypes |= VBOXVIDEOPORTPROCS_EVENT;
596 }
597 else
598 {
599 pCallbacks->pfnWaitForSingleObject = vboxWaitForSingleObjectVoid;
600 pCallbacks->pfnSetEvent = vboxSetEventVoid;
601 pCallbacks->pfnClearEvent = vboxClearEventVoid;
602 pCallbacks->pfnCreateEvent = vboxCreateEventVoid;
603 pCallbacks->pfnDeleteEvent = vboxDeleteEventVoid;
604 }
605
606 pCallbacks->pfnCreateSpinLock = (PFNCREATESPINLOCK)(pConfigInfo->VideoPortGetProcAddress)
607 (PrimaryExtension,
608 (PUCHAR)"VideoPortCreateSpinLock");
609 Assert(pCallbacks->pfnCreateSpinLock);
610
611 pCallbacks->pfnDeleteSpinLock = (PFNDELETESPINLOCK)(pConfigInfo->VideoPortGetProcAddress)
612 (PrimaryExtension,
613 (PUCHAR)"VideoPortDeleteSpinLock");
614 Assert(pCallbacks->pfnDeleteSpinLock);
615
616 pCallbacks->pfnAcquireSpinLock = (PFNACQUIRESPINLOCK)(pConfigInfo->VideoPortGetProcAddress)
617 (PrimaryExtension,
618 (PUCHAR)"VideoPortAcquireSpinLock");
619 Assert(pCallbacks->pfnAcquireSpinLock);
620
621 pCallbacks->pfnReleaseSpinLock = (PFNRELEASESPINLOCK)(pConfigInfo->VideoPortGetProcAddress)
622 (PrimaryExtension,
623 (PUCHAR)"VideoPortReleaseSpinLock");
624 Assert(pCallbacks->pfnReleaseSpinLock);
625
626 pCallbacks->pfnAcquireSpinLockAtDpcLevel = (PFNACQUIRESPINLOCKATDPCLEVEL)(pConfigInfo->VideoPortGetProcAddress)
627 (PrimaryExtension,
628 (PUCHAR)"VideoPortAcquireSpinLockAtDpcLevel");
629 Assert(pCallbacks->pfnAcquireSpinLockAtDpcLevel);
630
631 pCallbacks->pfnReleaseSpinLockFromDpcLevel = (PFNRELEASESPINLOCKFROMDPCLEVEL)(pConfigInfo->VideoPortGetProcAddress)
632 (PrimaryExtension,
633 (PUCHAR)"VideoPortReleaseSpinLockFromDpcLevel");
634 Assert(pCallbacks->pfnReleaseSpinLockFromDpcLevel);
635
636 if(pCallbacks->pfnCreateSpinLock
637 && pCallbacks->pfnDeleteSpinLock
638 && pCallbacks->pfnAcquireSpinLock
639 && pCallbacks->pfnReleaseSpinLock
640 && pCallbacks->pfnAcquireSpinLockAtDpcLevel
641 && pCallbacks->pfnReleaseSpinLockFromDpcLevel)
642 {
643 pCallbacks->fSupportedTypes |= VBOXVIDEOPORTPROCS_SPINLOCK;
644 }
645 else
646 {
647 pCallbacks->pfnCreateSpinLock = vboxCreateSpinLockVoid;
648 pCallbacks->pfnDeleteSpinLock = vboxDeleteSpinLockVoid;
649 pCallbacks->pfnAcquireSpinLock = vboxAcquireSpinLockVoid;
650 pCallbacks->pfnReleaseSpinLock = vboxReleaseSpinLockVoid;
651 pCallbacks->pfnAcquireSpinLockAtDpcLevel = vboxAcquireSpinLockAtDpcLevelVoid;
652 pCallbacks->pfnReleaseSpinLockFromDpcLevel = vboxReleaseSpinLockFromDpcLevelVoid;
653 }
654
655 pCallbacks->pfnAllocatePool = (PFNALLOCATEPOOL)(pConfigInfo->VideoPortGetProcAddress)
656 (PrimaryExtension,
657 (PUCHAR)"VideoPortAllocatePool");
658 Assert(pCallbacks->pfnAllocatePool);
659
660 pCallbacks->pfnFreePool = (PFNFREEPOOL)(pConfigInfo->VideoPortGetProcAddress)
661 (PrimaryExtension,
662 (PUCHAR)"VideoPortFreePool");
663 Assert(pCallbacks->pfnFreePool);
664
665 if(pCallbacks->pfnAllocatePool
666 && pCallbacks->pfnFreePool)
667 {
668 pCallbacks->fSupportedTypes |= VBOXVIDEOPORTPROCS_POOL;
669 }
670 else
671 {
672 pCallbacks->pfnAllocatePool = vboxAllocatePoolVoid;
673 pCallbacks->pfnFreePool = vboxFreePoolVoid;
674 }
675
676 pCallbacks->pfnQueueDpc = (PFNQUEUEDPC)(pConfigInfo->VideoPortGetProcAddress)
677 (PrimaryExtension,
678 (PUCHAR)"VideoPortQueueDpc");
679 Assert(pCallbacks->pfnQueueDpc);
680
681 if(pCallbacks->pfnQueueDpc)
682 {
683 pCallbacks->fSupportedTypes |= VBOXVIDEOPORTPROCS_DPC;
684 }
685 else
686 {
687 pCallbacks->pfnQueueDpc = vboxQueueDpcVoid;
688 }
689
690#ifdef DEBUG_misha
691 Assert(pCallbacks->fSupportedTypes & VBOXVIDEOPORTPROCS_EVENT);
692 Assert(pCallbacks->fSupportedTypes & VBOXVIDEOPORTPROCS_SPINLOCK);
693#endif
694}
695#endif
696
697/**
698 * Helper function to register secondary displays (DualView). Note that this will not
699 * be available on pre-XP versions, and some editions on XP will fail because they are
700 * intentionally crippled.
701 *
702 * HGSMI variant is a bit different because it uses only HGSMI interface (VBVA channel)
703 * to talk to the host.
704 */
705VOID VBoxSetupDisplaysHGSMI(PDEVICE_EXTENSION PrimaryExtension,
706#ifndef VBOX_WITH_WDDM
707 PVIDEO_PORT_CONFIG_INFO pConfigInfo,
708#endif
709 ULONG AdapterMemorySize, uint32_t fCaps)
710{
711 VP_STATUS rc = NO_ERROR;
712
713 dprintf(("VBoxVideo::VBoxSetupDisplays: PrimaryExtension = %p\n",
714 PrimaryExtension));
715
716 memset(commonFromDeviceExt(PrimaryExtension), 0,
717 sizeof(*commonFromDeviceExt(PrimaryExtension)));
718 commonFromDeviceExt(PrimaryExtension)->cbVRAM = AdapterMemorySize;
719 commonFromDeviceExt(PrimaryExtension)->fCaps = fCaps;
720 commonFromDeviceExt(PrimaryExtension)->cDisplays = 1;
721 commonFromDeviceExt(PrimaryExtension)->bHGSMI = VBoxHGSMIIsSupported ();
722 /* Why does this use VBoxVideoCmnMemZero? The MSDN docs say that it should
723 * only be used on mapped display adapter memory. Done with memset above. */
724 // VBoxVideoCmnMemZero(&commonFromDeviceExt(PrimaryExtension)->areaHostHeap, sizeof(HGSMIAREA));
725 if (commonFromDeviceExt(PrimaryExtension)->bHGSMI)
726 {
727 /** @note (michael) moved this here as it is done unconditionally in both
728 * driver branches. Feel free to fix if that is ever changed. */
729 commonFromDeviceExt(PrimaryExtension)->IOPortHost = (RTIOPORT)VGA_PORT_HGSMI_HOST;
730 commonFromDeviceExt(PrimaryExtension)->IOPortGuest = (RTIOPORT)VGA_PORT_HGSMI_GUEST;
731
732 /* Map the adapter information. It will be needed for HGSMI IO. */
733 rc = VBoxMapAdapterMemory (commonFromDeviceExt(PrimaryExtension),
734 &commonFromDeviceExt(PrimaryExtension)->pvAdapterInformation,
735 AdapterMemorySize - VBVA_ADAPTER_INFORMATION_SIZE,
736 VBVA_ADAPTER_INFORMATION_SIZE
737 );
738 if (rc != NO_ERROR)
739 {
740 dprintf(("VBoxVideo::VBoxSetupDisplays: VBoxMapAdapterMemory pvAdapterInfoirrmation failed rc = %d\n",
741 rc));
742
743 commonFromDeviceExt(PrimaryExtension)->bHGSMI = FALSE;
744 }
745 else
746 {
747 /* Setup a HGSMI heap within the adapter information area. */
748 rc = HGSMIHeapSetup (&commonFromDeviceExt(PrimaryExtension)->hgsmiAdapterHeap,
749 commonFromDeviceExt(PrimaryExtension)->pvAdapterInformation,
750 VBVA_ADAPTER_INFORMATION_SIZE - sizeof(HGSMIHOSTFLAGS),
751 commonFromDeviceExt(PrimaryExtension)->cbVRAM - VBVA_ADAPTER_INFORMATION_SIZE,
752 false /*fOffsetBased*/);
753
754 if (RT_FAILURE (rc))
755 {
756 dprintf(("VBoxVideo::VBoxSetupDisplays: HGSMIHeapSetup failed rc = %d\n",
757 rc));
758
759 commonFromDeviceExt(PrimaryExtension)->bHGSMI = FALSE;
760 }
761 else
762 {
763 commonFromDeviceExt(PrimaryExtension)->pHostFlags = (HGSMIHOSTFLAGS*)(((uint8_t*)commonFromDeviceExt(PrimaryExtension)->pvAdapterInformation)
764 + VBVA_ADAPTER_INFORMATION_SIZE - sizeof(HGSMIHOSTFLAGS));
765 }
766 }
767 }
768
769 /* Setup the host heap and the adapter memory. */
770 if (commonFromDeviceExt(PrimaryExtension)->bHGSMI)
771 {
772 /* The miniport heap is used for the host buffers. */
773 ULONG cbMiniportHeap = 0;
774 vboxQueryConfHGSMI (commonFromDeviceExt(PrimaryExtension), VBOX_VBVA_CONF32_HOST_HEAP_SIZE, &cbMiniportHeap);
775
776 if (cbMiniportHeap != 0)
777 {
778 /* Do not allow too big heap. No more than 25% of VRAM is allowed. */
779 ULONG cbMiniportHeapMaxSize = AdapterMemorySize / 4;
780
781 if (cbMiniportHeapMaxSize >= VBVA_ADAPTER_INFORMATION_SIZE)
782 {
783 cbMiniportHeapMaxSize -= VBVA_ADAPTER_INFORMATION_SIZE;
784 }
785
786 if (cbMiniportHeap > cbMiniportHeapMaxSize)
787 {
788 cbMiniportHeap = cbMiniportHeapMaxSize;
789 }
790
791 /* Round up to 4096 bytes. */
792 commonFromDeviceExt(PrimaryExtension)->cbMiniportHeap = (cbMiniportHeap + 0xFFF) & ~0xFFF;
793
794 dprintf(("VBoxVideo::VBoxSetupDisplays: cbMiniportHeap = 0x%08X, PrimaryExtension->u.primary.cbMiniportHeap = 0x%08X, cbMiniportHeapMaxSize = 0x%08X\n",
795 cbMiniportHeap, commonFromDeviceExt(PrimaryExtension)->cbMiniportHeap, cbMiniportHeapMaxSize));
796
797 /* Map the heap region.
798 *
799 * Note: the heap will be used for the host buffers submitted to the guest.
800 * The miniport driver is responsible for reading FIFO and notifying
801 * display drivers.
802 */
803 rc = VBoxMapAdapterMemory (commonFromDeviceExt(PrimaryExtension),
804 &commonFromDeviceExt(PrimaryExtension)->pvMiniportHeap,
805 commonFromDeviceExt(PrimaryExtension)->cbVRAM
806 - VBVA_ADAPTER_INFORMATION_SIZE
807 - commonFromDeviceExt(PrimaryExtension)->cbMiniportHeap,
808 commonFromDeviceExt(PrimaryExtension)->cbMiniportHeap
809 );
810 if (rc != NO_ERROR)
811 {
812 commonFromDeviceExt(PrimaryExtension)->pvMiniportHeap = NULL;
813 commonFromDeviceExt(PrimaryExtension)->cbMiniportHeap = 0;
814 commonFromDeviceExt(PrimaryExtension)->bHGSMI = FALSE;
815 }
816 else
817 {
818 HGSMIOFFSET offBase = commonFromDeviceExt(PrimaryExtension)->cbVRAM
819 - VBVA_ADAPTER_INFORMATION_SIZE
820 - commonFromDeviceExt(PrimaryExtension)->cbMiniportHeap;
821
822 /* Init the host hap area. Buffers from the host will be placed there. */
823 HGSMIAreaInitialize (&commonFromDeviceExt(PrimaryExtension)->areaHostHeap,
824 commonFromDeviceExt(PrimaryExtension)->pvMiniportHeap,
825 commonFromDeviceExt(PrimaryExtension)->cbMiniportHeap,
826 offBase);
827 }
828 }
829 else
830 {
831 /* Host has not requested a heap. */
832 commonFromDeviceExt(PrimaryExtension)->pvMiniportHeap = NULL;
833 commonFromDeviceExt(PrimaryExtension)->cbMiniportHeap = 0;
834 }
835 }
836
837 /* Check whether the guest supports multimonitors. */
838 if (commonFromDeviceExt(PrimaryExtension)->bHGSMI)
839 {
840 /* Query the configured number of displays. */
841 ULONG cDisplays = 0;
842 vboxQueryConfHGSMI (commonFromDeviceExt(PrimaryExtension), VBOX_VBVA_CONF32_MONITOR_COUNT, &cDisplays);
843
844 dprintf(("VBoxVideo::VBoxSetupDisplays: cDisplays = %d\n",
845 cDisplays));
846
847 if (cDisplays == 0 || cDisplays > VBOX_VIDEO_MAX_SCREENS)
848 {
849 /* Host reported some bad value. Continue in the 1 screen mode. */
850 cDisplays = 1;
851 }
852 commonFromDeviceExt(PrimaryExtension)->cDisplays = cDisplays;
853 }
854
855 if (commonFromDeviceExt(PrimaryExtension)->bHGSMI)
856 {
857 /* Setup the information for the host. */
858 rc = vboxSetupAdapterInfoHGSMI (commonFromDeviceExt(PrimaryExtension));
859
860 if (RT_FAILURE (rc))
861 {
862 commonFromDeviceExt(PrimaryExtension)->bHGSMI = FALSE;
863 }
864 }
865
866#ifndef VBOX_WITH_WDDM
867 /* For WDDM, we simply store the number of monitors as we will deal with
868 * VidPN stuff later */
869 if (commonFromDeviceExt(PrimaryExtension)->bHGSMI)
870 {
871 typedef VP_STATUS (*PFNCREATESECONDARYDISPLAY)(PVOID, PVOID *, ULONG);
872 PFNCREATESECONDARYDISPLAY pfnCreateSecondaryDisplay = NULL;
873
874 /* Dynamically query the VideoPort import to be binary compatible across Windows versions */
875 if (vboxQueryWinVersion() > WINNT4)
876 {
877 /* This bluescreens on NT4, hence the above version check */
878 pfnCreateSecondaryDisplay = (PFNCREATESECONDARYDISPLAY)(pConfigInfo->VideoPortGetProcAddress)
879 (PrimaryExtension,
880 (PUCHAR)"VideoPortCreateSecondaryDisplay");
881 }
882
883 if (!pfnCreateSecondaryDisplay)
884 commonFromDeviceExt(PrimaryExtension)->cDisplays = 1;
885 else
886 {
887 PDEVICE_EXTENSION pPrev = PrimaryExtension;
888
889 ULONG iDisplay;
890 ULONG cDisplays = commonFromDeviceExt(PrimaryExtension)->cDisplays;
891 commonFromDeviceExt(PrimaryExtension)->cDisplays = 1;
892 for (iDisplay = 1; iDisplay < cDisplays; iDisplay++)
893 {
894 PDEVICE_EXTENSION SecondaryExtension = NULL;
895 rc = pfnCreateSecondaryDisplay (PrimaryExtension, (PVOID*)&SecondaryExtension, VIDEO_DUALVIEW_REMOVABLE);
896
897 dprintf(("VBoxVideo::VBoxSetupDisplays: VideoPortCreateSecondaryDisplay returned %#x, SecondaryExtension = %p\n",
898 rc, SecondaryExtension));
899
900 if (rc != NO_ERROR)
901 {
902 break;
903 }
904
905 SecondaryExtension->pNext = NULL;
906 SecondaryExtension->pPrimary = PrimaryExtension;
907 SecondaryExtension->iDevice = iDisplay;
908 SecondaryExtension->ulFrameBufferOffset = 0;
909 SecondaryExtension->ulFrameBufferSize = 0;
910 SecondaryExtension->u.secondary.bEnabled = FALSE;
911
912 /* Update the list pointers. */
913 pPrev->pNext = SecondaryExtension;
914 pPrev = SecondaryExtension;
915
916 /* Take the successfully created display into account. */
917 commonFromDeviceExt(PrimaryExtension)->cDisplays++;
918 }
919 }
920
921 /* Failure to create secondary displays is not fatal */
922 rc = NO_ERROR;
923 }
924
925 /* Now when the number of monitors is known and extensions are created,
926 * calculate the layout of framebuffers.
927 */
928 VBoxComputeFrameBufferSizes (PrimaryExtension);
929 /* in case of WDDM we do not control the framebuffer location,
930 * i.e. it is assigned by Video Memory Manager,
931 * The FB information should be passed to guest from our
932 * DxgkDdiSetVidPnSourceAddress callback */
933
934 if (commonFromDeviceExt(PrimaryExtension)->bHGSMI)
935 {
936 if (RT_SUCCESS(rc))
937 {
938 rc = VBoxHGSMISendViewInfo (commonFromDeviceExt(PrimaryExtension),
939 commonFromDeviceExt(PrimaryExtension)->cDisplays,
940 vbvaInitInfoDisplay,
941 (void *) PrimaryExtension);
942 AssertRC(rc);
943 }
944
945 if (RT_FAILURE (rc))
946 {
947 commonFromDeviceExt(PrimaryExtension)->bHGSMI = FALSE;
948 }
949 }
950#endif
951
952#ifdef VBOX_WITH_WDDM
953 if (commonFromDeviceExt(PrimaryExtension)->bHGSMI)
954 {
955 ULONG ulAvailable = commonFromDeviceExt(PrimaryExtension)->cbVRAM
956 - commonFromDeviceExt(PrimaryExtension)->cbMiniportHeap
957 - VBVA_ADAPTER_INFORMATION_SIZE;
958
959 ULONG ulSize;
960 ULONG offset;
961#ifdef VBOX_WITH_VDMA
962 ulSize = ulAvailable / 2;
963 if (ulSize > VBOXWDDM_C_VDMA_BUFFER_SIZE)
964 ulSize = VBOXWDDM_C_VDMA_BUFFER_SIZE;
965
966 /* Align down to 4096 bytes. */
967 ulSize &= ~0xFFF;
968 offset = ulAvailable - ulSize;
969
970 Assert(!(offset & 0xFFF));
971#else
972 offset = ulAvailable;
973#endif
974 rc = vboxVdmaCreate (PrimaryExtension, &PrimaryExtension->u.primary.Vdma
975#ifdef VBOX_WITH_VDMA
976 , offset, ulSize
977#endif
978 );
979 AssertRC(rc);
980 if (RT_SUCCESS(rc))
981 {
982 /* can enable it right away since the host does not need any screen/FB info
983 * for basic DMA functionality */
984 rc = vboxVdmaEnable(PrimaryExtension, &PrimaryExtension->u.primary.Vdma);
985 AssertRC(rc);
986 if (RT_FAILURE(rc))
987 vboxVdmaDestroy(PrimaryExtension, &PrimaryExtension->u.primary.Vdma);
988 }
989
990#ifdef VBOXWDDM_RENDER_FROM_SHADOW
991 if (RT_SUCCESS(rc))
992 {
993 ulAvailable = offset;
994 ulSize = ulAvailable / 2;
995 ulSize /= commonFromDeviceExt(PrimaryExtension)->cDisplays;
996 Assert(ulSize > VBVA_MIN_BUFFER_SIZE);
997 if (ulSize > VBVA_MIN_BUFFER_SIZE)
998 {
999 ULONG ulRatio = ulSize/VBVA_MIN_BUFFER_SIZE;
1000 ulRatio >>= 4; /* /= 16; */
1001 if (ulRatio)
1002 ulSize = VBVA_MIN_BUFFER_SIZE * ulRatio;
1003 else
1004 ulSize = VBVA_MIN_BUFFER_SIZE;
1005 }
1006 else
1007 {
1008 /* todo: ?? */
1009 }
1010
1011 ulSize &= ~0xFFF;
1012 Assert(ulSize);
1013
1014 Assert(ulSize * commonFromDeviceExt(PrimaryExtension)->cDisplays < ulAvailable);
1015
1016 for (int i = commonFromDeviceExt(PrimaryExtension)->cDisplays-1; i >= 0; --i)
1017 {
1018 offset -= ulSize;
1019 rc = vboxVbvaCreate(PrimaryExtension, &PrimaryExtension->aSources[i].Vbva, offset, ulSize, i);
1020 AssertRC(rc);
1021 if (RT_SUCCESS(rc))
1022 {
1023 rc = vboxVbvaEnable(PrimaryExtension, &PrimaryExtension->aSources[i].Vbva);
1024 AssertRC(rc);
1025 if (RT_FAILURE(rc))
1026 {
1027 /* @todo: de-initialize */
1028 }
1029 }
1030 }
1031 }
1032#endif
1033
1034 rc = VBoxMapAdapterMemory(commonFromDeviceExt(PrimaryExtension), (void**)&PrimaryExtension->pvVisibleVram,
1035 0,
1036 vboxWddmVramCpuVisibleSize(PrimaryExtension));
1037 Assert(rc == VINF_SUCCESS);
1038 if (rc != VINF_SUCCESS)
1039 PrimaryExtension->pvVisibleVram = NULL;
1040
1041 if (RT_FAILURE(rc))
1042 commonFromDeviceExt(PrimaryExtension)->bHGSMI = FALSE;
1043 }
1044#endif
1045
1046 if (!commonFromDeviceExt(PrimaryExtension)->bHGSMI)
1047 {
1048 /* Unmap the memory if VBoxVideo is not supported. */
1049 VBoxUnmapAdapterMemory (PrimaryExtension, &commonFromDeviceExt(PrimaryExtension)->pvMiniportHeap, commonFromDeviceExt(PrimaryExtension)->cbMiniportHeap);
1050 VBoxUnmapAdapterInformation (PrimaryExtension);
1051
1052 HGSMIHeapDestroy (&commonFromDeviceExt(PrimaryExtension)->hgsmiAdapterHeap);
1053 }
1054
1055 if (commonFromDeviceExt(PrimaryExtension)->bHGSMI)
1056 {
1057 VBoxVideoCmnSpinLockCreate(PrimaryExtension, &PrimaryExtension->u.primary.pSynchLock);
1058 }
1059
1060 dprintf(("VBoxVideo::VBoxSetupDisplays: finished\n"));
1061}
1062
1063#ifdef VBOX_WITH_WDDM
1064int VBoxFreeDisplaysHGSMI(PDEVICE_EXTENSION PrimaryExtension)
1065{
1066 int rc = VINF_SUCCESS;
1067
1068 Assert(PrimaryExtension->pvVisibleVram);
1069 if (PrimaryExtension->pvVisibleVram)
1070 VBoxUnmapAdapterMemory(PrimaryExtension, (void**)&PrimaryExtension->pvVisibleVram, vboxWddmVramCpuVisibleSize(PrimaryExtension));
1071
1072 for (int i = commonFromDeviceExt(PrimaryExtension)->cDisplays-1; i >= 0; --i)
1073 {
1074 rc = vboxVbvaDisable(PrimaryExtension, &PrimaryExtension->aSources[i].Vbva);
1075 AssertRC(rc);
1076 if (RT_SUCCESS(rc))
1077 {
1078 rc = vboxVbvaDestroy(PrimaryExtension, &PrimaryExtension->aSources[i].Vbva);
1079 AssertRC(rc);
1080 if (RT_FAILURE(rc))
1081 {
1082 /* @todo: */
1083 }
1084 }
1085 }
1086
1087 rc = vboxVdmaDisable(PrimaryExtension, &PrimaryExtension->u.primary.Vdma);
1088 AssertRC(rc);
1089 if (RT_SUCCESS(rc))
1090 {
1091 rc = vboxVdmaDestroy(PrimaryExtension, &PrimaryExtension->u.primary.Vdma);
1092 AssertRC(rc);
1093 if (RT_SUCCESS(rc))
1094 {
1095 /*rc = */VBoxUnmapAdapterMemory(PrimaryExtension, &commonFromDeviceExt(PrimaryExtension)->pvMiniportHeap, commonFromDeviceExt(PrimaryExtension)->cbMiniportHeap);
1096/*
1097 AssertRC(rc);
1098 if (RT_SUCCESS(rc))
1099*/
1100 {
1101 HGSMIHeapDestroy(&commonFromDeviceExt(PrimaryExtension)->hgsmiAdapterHeap);
1102
1103 /* Map the adapter information. It will be needed for HGSMI IO. */
1104 /*rc = */VBoxUnmapAdapterInformation(PrimaryExtension);
1105/*
1106 AssertRC(rc);
1107 if (RT_FAILURE(rc))
1108 drprintf((__FUNCTION__"VBoxUnmapAdapterMemory PrimaryExtension->u.primary.pvAdapterInformation failed, rc(%d)\n", rc));
1109*/
1110
1111 }
1112 }
1113 }
1114
1115 return rc;
1116}
1117#endif
1118
1119/*
1120 * Send the pointer shape to the host.
1121 */
1122typedef struct _MOUSEPOINTERSHAPECTX
1123{
1124 VIDEO_POINTER_ATTRIBUTES *pPointerAttr;
1125 uint32_t cbData;
1126 int32_t i32Result;
1127} MOUSEPOINTERSHAPECTX;
1128
1129static int vbvaInitMousePointerShape (PVBOXVIDEO_COMMON, void *pvContext, void *pvData)
1130{
1131 MOUSEPOINTERSHAPECTX *pCtx = (MOUSEPOINTERSHAPECTX *)pvContext;
1132 VBVAMOUSEPOINTERSHAPE *p = (VBVAMOUSEPOINTERSHAPE *)pvData;
1133
1134 /* Will be updated by the host. */
1135 p->i32Result = VINF_SUCCESS;
1136
1137 /* We have our custom flags in the field */
1138 p->fu32Flags = pCtx->pPointerAttr->Enable & 0x0000FFFF;
1139
1140 p->u32HotX = (pCtx->pPointerAttr->Enable >> 16) & 0xFF;
1141 p->u32HotY = (pCtx->pPointerAttr->Enable >> 24) & 0xFF;
1142 p->u32Width = pCtx->pPointerAttr->Width;
1143 p->u32Height = pCtx->pPointerAttr->Height;
1144
1145 if (p->fu32Flags & VBOX_MOUSE_POINTER_SHAPE)
1146 {
1147 /* If shape is supplied, then alway create the pointer visible.
1148 * See comments in 'vboxUpdatePointerShape'
1149 */
1150 p->fu32Flags |= VBOX_MOUSE_POINTER_VISIBLE;
1151
1152 /* Copy the actual pointer data. */
1153 memcpy (p->au8Data, pCtx->pPointerAttr->Pixels, pCtx->cbData);
1154 }
1155
1156 return VINF_SUCCESS;
1157}
1158
1159static int vbvaFinalizeMousePointerShape (PVBOXVIDEO_COMMON, void *pvContext, void *pvData)
1160{
1161 MOUSEPOINTERSHAPECTX *pCtx = (MOUSEPOINTERSHAPECTX *)pvContext;
1162 VBVAMOUSEPOINTERSHAPE *p = (VBVAMOUSEPOINTERSHAPE *)pvData;
1163
1164 pCtx->i32Result = p->i32Result;
1165
1166 return VINF_SUCCESS;
1167}
1168
1169BOOLEAN vboxUpdatePointerShape (PDEVICE_EXTENSION DeviceExtension,
1170 PVIDEO_POINTER_ATTRIBUTES pointerAttr,
1171 uint32_t cbLength)
1172{
1173#ifndef VBOX_WITH_WDDM
1174 PDEVICE_EXTENSION PrimaryExtension = DeviceExtension->pPrimary;
1175
1176 /* In multimonitor case the HW mouse pointer is the same on all screens,
1177 * and Windows calls each display driver with the same pointer data: visible for
1178 * the screen where the pointer is and invisible for other screens.
1179 *
1180 * This driver passes the shape to the host only from primary screen and makes
1181 * the pointer always visible (in vbvaInitMousePointerShape).
1182 *
1183 * The simple solution makes it impossible to create the shape and keep the mouse
1184 * pointer invisible. New shapes will be created visible.
1185 * But:
1186 * 1) VBox frontends actually ignore the visibility flag if VBOX_MOUSE_POINTER_SHAPE
1187 * is set and always create new pointers visible.
1188 * 2) Windows uses DrvMovePointer to hide the pointer, which will still work.
1189 */
1190
1191 if (DeviceExtension->iDevice != PrimaryExtension->iDevice)
1192 {
1193 dprintf(("vboxUpdatePointerShape: ignore non primary device %d(%d)\n",
1194 DeviceExtension->iDevice, PrimaryExtension->iDevice));
1195 /* Success. */
1196 return TRUE;
1197 }
1198#else
1199 PDEVICE_EXTENSION PrimaryExtension = DeviceExtension;
1200#endif
1201
1202 uint32_t cbData = 0;
1203
1204 if (pointerAttr->Enable & VBOX_MOUSE_POINTER_SHAPE)
1205 {
1206 /* Size of the pointer data: sizeof (AND mask) + sizeof (XOR_MASK) */
1207 cbData = ((((pointerAttr->Width + 7) / 8) * pointerAttr->Height + 3) & ~3)
1208 + pointerAttr->Width * 4 * pointerAttr->Height;
1209 }
1210
1211#ifndef DEBUG_misha
1212 dprintf(("vboxUpdatePointerShape: cbData %d, %dx%d\n",
1213 cbData, pointerAttr->Width, pointerAttr->Height));
1214#endif
1215
1216 if (cbData > cbLength - sizeof(VIDEO_POINTER_ATTRIBUTES))
1217 {
1218 dprintf(("vboxUpdatePointerShape: calculated pointer data size is too big (%d bytes, limit %d)\n",
1219 cbData, cbLength - sizeof(VIDEO_POINTER_ATTRIBUTES)));
1220 return FALSE;
1221 }
1222
1223 MOUSEPOINTERSHAPECTX ctx;
1224
1225 ctx.pPointerAttr = pointerAttr;
1226 ctx.cbData = cbData;
1227 ctx.i32Result = VERR_NOT_SUPPORTED;
1228
1229 int rc = vboxCallVBVA (commonFromDeviceExt(PrimaryExtension),
1230 VBVA_MOUSE_POINTER_SHAPE,
1231 sizeof (VBVAMOUSEPOINTERSHAPE) + cbData,
1232 vbvaInitMousePointerShape,
1233 vbvaFinalizeMousePointerShape,
1234 &ctx);
1235#ifndef DEBUG_misha
1236 dprintf(("VBoxVideo::vboxMousePointerShape: rc %d, i32Result = %d\n", rc, ctx.i32Result));
1237#endif
1238
1239 return RT_SUCCESS(rc) && RT_SUCCESS(ctx.i32Result);
1240}
1241
1242#ifndef VBOX_WITH_WDDM
1243typedef struct _VBVAMINIPORT_CHANNELCONTEXT
1244{
1245 PFNHGSMICHANNELHANDLER pfnChannelHandler;
1246 void *pvChannelHandler;
1247}VBVAMINIPORT_CHANNELCONTEXT;
1248
1249typedef struct _VBVADISP_CHANNELCONTEXT
1250{
1251 struct _VBVAHOSTCMD * pFirstCmd;
1252 struct _VBVAHOSTCMD * pLastCmd;
1253 VBOXVCMNSPIN_LOCK pSynchLock;
1254#ifdef DEBUG
1255 int cCmds;
1256#endif
1257 bool bValid;
1258}VBVADISP_CHANNELCONTEXT;
1259
1260#ifdef DEBUG
1261void dbgCheckListLocked(const VBVADISP_CHANNELCONTEXT *pList, struct _VBVAHOSTCMD * pCmd)
1262{
1263 int counter = 0;
1264 for(struct _VBVAHOSTCMD * pCur = pList->pFirstCmd; pCur; pCur=pCur->u.pNext)
1265 {
1266 Assert(pCur != pCmd);
1267 if(pCur == pList->pLastCmd)
1268 {
1269 Assert(pCur->u.pNext == NULL);
1270 }
1271 if(pCur->u.pNext == NULL)
1272 {
1273 Assert(pCur == pList->pLastCmd);
1274 }
1275 counter++;
1276 }
1277
1278 Assert(counter == pList->cCmds);
1279}
1280
1281void dbgCheckList(PDEVICE_EXTENSION PrimaryExtension, VBVADISP_CHANNELCONTEXT *pList, struct _VBVAHOSTCMD * pCmd)
1282{
1283 VBOXVCMNIRQL oldIrql;
1284 VBoxVideoCmnSpinLockAcquire(PrimaryExtension, &pList->pSynchLock, &oldIrql);
1285
1286 dbgCheckListLocked(pList, pCmd);
1287
1288 VBoxVideoCmnSpinLockRelease(PrimaryExtension, &pList->pSynchLock, oldIrql);
1289}
1290
1291#define DBG_CHECKLIST_LOCKED(_pl, pc) dbgCheckListLocked(_pl, pc)
1292#define DBG_CHECKLIST(_pe, _pl, pc) dbgCheckList(_pe, _pl, pc)
1293
1294#else
1295#define DBG_CHECKLIST_LOCKED(_pl, pc) do{}while(0)
1296#define DBG_CHECKLIST(_pe, _pl, pc) do{}while(0)
1297#endif
1298
1299
1300typedef struct _VBVA_CHANNELCONTEXTS
1301{
1302 PDEVICE_EXTENSION PrimaryExtension;
1303 uint32_t cUsed;
1304 uint32_t cContexts;
1305 VBVAMINIPORT_CHANNELCONTEXT mpContext;
1306 VBVADISP_CHANNELCONTEXT aContexts[1];
1307}VBVA_CHANNELCONTEXTS;
1308
1309static int vboxVBVADeleteChannelContexts(PDEVICE_EXTENSION PrimaryExtension, VBVA_CHANNELCONTEXTS * pContext)
1310{
1311 VBoxVideoCmnMemFree(PrimaryExtension,pContext);
1312 return VINF_SUCCESS;
1313}
1314
1315static int vboxVBVACreateChannelContexts(PDEVICE_EXTENSION PrimaryExtension, VBVA_CHANNELCONTEXTS ** ppContext)
1316{
1317 uint32_t cDisplays = (uint32_t)commonFromDeviceExt(PrimaryExtension)->cDisplays;
1318 const size_t size = RT_OFFSETOF(VBVA_CHANNELCONTEXTS, aContexts[cDisplays]);
1319 VBVA_CHANNELCONTEXTS * pContext = (VBVA_CHANNELCONTEXTS*)VBoxVideoCmnMemAllocNonPaged(PrimaryExtension, size, MEM_TAG);
1320 if(pContext)
1321 {
1322 memset(pContext, 0, size);
1323 pContext->cContexts = cDisplays;
1324 pContext->PrimaryExtension = PrimaryExtension;
1325 *ppContext = pContext;
1326 return VINF_SUCCESS;
1327 }
1328 return VERR_GENERAL_FAILURE;
1329}
1330
1331static VBVADISP_CHANNELCONTEXT* vboxVBVAFindHandlerInfo(VBVA_CHANNELCONTEXTS *pCallbacks, int iId)
1332{
1333 if(iId < 0)
1334 {
1335 return NULL;
1336 }
1337 else if(pCallbacks->cContexts > (uint32_t)iId)
1338 {
1339 return &pCallbacks->aContexts[iId];
1340 }
1341 return NULL;
1342}
1343
1344DECLCALLBACK(void) hgsmiHostCmdComplete (HVBOXVIDEOHGSMI hHGSMI, struct _VBVAHOSTCMD * pCmd)
1345{
1346 PDEVICE_EXTENSION PrimaryExtension = ((PDEVICE_EXTENSION)hHGSMI)->pPrimary;
1347 HGSMIHostCmdComplete (commonFromDeviceExt(PrimaryExtension), pCmd);
1348}
1349
1350DECLCALLBACK(int) hgsmiHostCmdRequest (HVBOXVIDEOHGSMI hHGSMI, uint8_t u8Channel, struct _VBVAHOSTCMD ** ppCmd)
1351{
1352// if(display < 0)
1353// return VERR_INVALID_PARAMETER;
1354 if(!ppCmd)
1355 return VERR_INVALID_PARAMETER;
1356
1357 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)hHGSMI;
1358 PDEVICE_EXTENSION PrimaryExtension = pDevExt->pPrimary;
1359
1360 /* pick up the host commands */
1361 VBoxVideoHGSMIDpc(PrimaryExtension, NULL);
1362
1363 HGSMICHANNEL * pChannel = HGSMIChannelFindById (&commonFromDeviceExt(PrimaryExtension)->channels, u8Channel);
1364 if(pChannel)
1365 {
1366 VBVA_CHANNELCONTEXTS * pContexts = (VBVA_CHANNELCONTEXTS *)pChannel->handler.pvHandler;
1367 VBVADISP_CHANNELCONTEXT *pDispContext = vboxVBVAFindHandlerInfo(pContexts, pDevExt->iDevice);
1368 Assert(pDispContext);
1369 if(pDispContext)
1370 {
1371 UCHAR oldIrql;
1372 VBoxVideoCmnSpinLockAcquire(PrimaryExtension, &pDispContext->pSynchLock, &oldIrql);
1373
1374 DBG_CHECKLIST_LOCKED(pDispContext, NULL);
1375
1376 *ppCmd = pDispContext->pFirstCmd;
1377 pDispContext->pFirstCmd = NULL;
1378 pDispContext->pLastCmd = NULL;
1379#ifdef DEBUG
1380 pDispContext->cCmds = 0;
1381#endif
1382 VBoxVideoCmnSpinLockRelease(PrimaryExtension, &pDispContext->pSynchLock, oldIrql);
1383
1384 DBG_CHECKLIST(PrimaryExtension, pDispContext, NULL);
1385
1386 return VINF_SUCCESS;
1387 }
1388 }
1389
1390 return VERR_INVALID_PARAMETER;
1391}
1392
1393static DECLCALLBACK(int) vboxVBVAChannelGenericHandler(void *pvHandler, uint16_t u16ChannelInfo, void *pvBuffer, HGSMISIZE cbBuffer)
1394{
1395 VBVA_CHANNELCONTEXTS *pCallbacks = (VBVA_CHANNELCONTEXTS*)pvHandler;
1396// Assert(0);
1397 Assert(cbBuffer > VBVAHOSTCMD_HDRSIZE);
1398 if(cbBuffer > VBVAHOSTCMD_HDRSIZE)
1399 {
1400 VBVAHOSTCMD *pHdr = (VBVAHOSTCMD*)pvBuffer;
1401 Assert(pHdr->iDstID >= 0);
1402 if(pHdr->iDstID >= 0)
1403 {
1404 VBVADISP_CHANNELCONTEXT* pHandler = vboxVBVAFindHandlerInfo(pCallbacks, pHdr->iDstID);
1405 Assert(pHandler && pHandler->bValid);
1406 if(pHandler && pHandler->bValid)
1407 {
1408 VBVAHOSTCMD *pFirst = NULL, *pLast = NULL;
1409 for(VBVAHOSTCMD *pCur = pHdr; pCur; )
1410 {
1411 Assert(!pCur->u.Data);
1412 Assert(!pFirst);
1413 Assert(!pLast);
1414
1415 switch(u16ChannelInfo)
1416 {
1417 case VBVAHG_DISPLAY_CUSTOM:
1418 {
1419 if(pLast)
1420 {
1421 pLast->u.pNext = pCur;
1422 pLast = pCur;
1423 }
1424 else
1425 {
1426 pFirst = pCur;
1427 pLast = pCur;
1428 }
1429 Assert(!pCur->u.Data);
1430 //TODO: use offset here
1431 pCur = pCur->u.pNext;
1432 Assert(!pCur);
1433 Assert(pFirst);
1434 Assert(pFirst == pLast);
1435 break;
1436 }
1437 case VBVAHG_EVENT:
1438 {
1439 VBVAHOSTCMDEVENT *pEventCmd = VBVAHOSTCMD_BODY(pCur, VBVAHOSTCMDEVENT);
1440#ifndef VBOX_WITH_WDDM
1441 PEVENT pEvent = (PEVENT)pEventCmd->pEvent;
1442 pCallbacks->PrimaryExtension->u.primary.VideoPortProcs.pfnSetEvent(
1443 pCallbacks->PrimaryExtension,
1444 pEvent);
1445#else
1446 PKEVENT pEvent = (PKEVENT)pEventCmd->pEvent;
1447 KeSetEvent(pEvent, 0, FALSE);
1448#endif
1449 }
1450 default:
1451 {
1452 DBG_CHECKLIST(pCallbacks->PrimaryExtension, pHandler, pCur);
1453 Assert(u16ChannelInfo==VBVAHG_EVENT);
1454 Assert(!pCur->u.Data);
1455 //TODO: use offset here
1456 if(pLast)
1457 pLast->u.pNext = pCur->u.pNext;
1458 VBVAHOSTCMD * pNext = pCur->u.pNext;
1459 pCur->u.pNext = NULL;
1460 HGSMIHostCmdComplete(commonFromDeviceExt(pCallbacks->PrimaryExtension), pCur);
1461 pCur = pNext;
1462 Assert(!pCur);
1463 Assert(!pFirst);
1464 Assert(pFirst == pLast);
1465 break;
1466 }
1467 }
1468 }
1469
1470 DBG_CHECKLIST(pCallbacks->PrimaryExtension, pHandler, pFirst);
1471
1472 /* we do not support lists currently */
1473 Assert(pFirst == pLast);
1474 if(pLast)
1475 {
1476 Assert(pLast->u.pNext == NULL);
1477 }
1478
1479 if(pFirst)
1480 {
1481 Assert(pLast);
1482 UCHAR oldIrql;
1483 VBoxVideoCmnSpinLockAcquire(pCallbacks->PrimaryExtension,
1484 &pHandler->pSynchLock,
1485 &oldIrql);
1486
1487 DBG_CHECKLIST_LOCKED(pHandler, pFirst);
1488
1489 if(pHandler->pLastCmd)
1490 {
1491 pHandler->pLastCmd->u.pNext = pFirst;
1492 Assert(pHandler->pFirstCmd);
1493 }
1494 else
1495 {
1496 Assert(!pHandler->pFirstCmd);
1497 pHandler->pFirstCmd = pFirst;
1498 }
1499 pHandler->pLastCmd = pLast;
1500#ifdef DEBUG
1501 pHandler->cCmds++;
1502#endif
1503 DBG_CHECKLIST_LOCKED(pHandler, NULL);
1504
1505 VBoxVideoCmnSpinLockRelease(pCallbacks->PrimaryExtension,
1506 &pHandler->pSynchLock,
1507 oldIrql);
1508 }
1509 else
1510 {
1511 Assert(!pLast);
1512 }
1513 return VINF_SUCCESS;
1514 }
1515 }
1516 else
1517 {
1518 //TODO: impl
1519// HGSMIMINIPORT_CHANNELCONTEXT *pHandler = vboxVideoHGSMIFindHandler;
1520// if(pHandler && pHandler->pfnChannelHandler)
1521// {
1522// pHandler->pfnChannelHandler(pHandler->pvChannelHandler, u16ChannelInfo, pHdr, cbBuffer);
1523//
1524// return VINF_SUCCESS;
1525// }
1526 }
1527 }
1528 /* no handlers were found, need to complete the command here */
1529 HGSMIHostCmdComplete(commonFromDeviceExt(pCallbacks->PrimaryExtension), pvBuffer);
1530 return VINF_SUCCESS;
1531}
1532
1533static HGSMICHANNELHANDLER g_OldHandler;
1534
1535int vboxVBVAChannelDisplayEnable(PDEVICE_EXTENSION PrimaryExtension,
1536 int iDisplay, /* negative would mean this is a miniport handler */
1537 uint8_t u8Channel)
1538{
1539 VBVA_CHANNELCONTEXTS * pContexts;
1540 HGSMICHANNEL * pChannel = HGSMIChannelFindById (&commonFromDeviceExt(PrimaryExtension)->channels, u8Channel);
1541 if(!pChannel)
1542 {
1543 int rc = vboxVBVACreateChannelContexts(PrimaryExtension, &pContexts);
1544 if(RT_FAILURE(rc))
1545 {
1546 return rc;
1547 }
1548 }
1549 else
1550 {
1551 pContexts = (VBVA_CHANNELCONTEXTS *)pChannel->handler.pvHandler;
1552 }
1553
1554 VBVADISP_CHANNELCONTEXT *pDispContext = vboxVBVAFindHandlerInfo(pContexts, iDisplay);
1555 Assert(pDispContext);
1556 if(pDispContext)
1557 {
1558#ifdef DEBUGVHWASTRICT
1559 Assert(!pDispContext->bValid);
1560#endif
1561 Assert(!pDispContext->pFirstCmd);
1562 Assert(!pDispContext->pLastCmd);
1563 if(!pDispContext->bValid)
1564 {
1565 pDispContext->bValid = true;
1566 pDispContext->pFirstCmd = NULL;
1567 pDispContext->pLastCmd= NULL;
1568#ifdef DEBUG
1569 pDispContext->cCmds = 0;
1570#endif
1571
1572 VBoxVideoCmnSpinLockCreate(PrimaryExtension, &pDispContext->pSynchLock);
1573
1574 int rc = VINF_SUCCESS;
1575 if(!pChannel)
1576 {
1577 rc = HGSMIChannelRegister (&commonFromDeviceExt(PrimaryExtension)->channels,
1578 u8Channel,
1579 "VGA Miniport HGSMI channel",
1580 vboxVBVAChannelGenericHandler,
1581 pContexts,
1582 &g_OldHandler);
1583 }
1584
1585 if(RT_SUCCESS(rc))
1586 {
1587 pContexts->cUsed++;
1588 return VINF_SUCCESS;
1589 }
1590 }
1591 }
1592
1593 if(!pChannel)
1594 {
1595 vboxVBVADeleteChannelContexts(PrimaryExtension, pContexts);
1596 }
1597
1598 return VERR_GENERAL_FAILURE;
1599}
1600#endif /* !VBOX_WITH_WDDM */
1601
1602/** @todo Mouse pointer position to be read from VMMDev memory, address of the memory region
1603 * can be queried from VMMDev via an IOCTL. This VMMDev memory region will contain
1604 * host information which is needed by the guest.
1605 *
1606 * Reading will not cause a switch to the host.
1607 *
1608 * Have to take into account:
1609 * * synchronization: host must write to the memory only from EMT,
1610 * large structures must be read under flag, which tells the host
1611 * that the guest is currently reading the memory (OWNER flag?).
1612 * * guest writes: may be allocate a page for the host info and make
1613 * the page readonly for the guest.
1614 * * the information should be available only for additions drivers.
1615 * * VMMDev additions driver will inform the host which version of the info it expects,
1616 * host must support all versions.
1617 *
1618 */
1619
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