VirtualBox

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

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

Additions/WINNT/Graphics: more refactoring

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 55.5 KB
Line 
1/* $Id: VBoxVideoHGSMI.cpp 33226 2010-10-19 10:37:24Z 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, &commonFromDeviceExt(PrimaryExtension)->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, &commonFromDeviceExt(PrimaryExtension)->pSynchLock, flags, OldIrql);
134 break;
135 }
136 VBOX_HGSMI_UNLOCK(PrimaryExtension, &commonFromDeviceExt(PrimaryExtension)->pSynchLock, flags, OldIrql);
137 }
138 else
139 {
140 if(!bProcessing)
141 {
142 VBOX_HGSMI_LOCK(PrimaryExtension, &commonFromDeviceExt(PrimaryExtension)->pSynchLock, flags, &OldIrql);
143 if(!(commonFromDeviceExt(PrimaryExtension)->pHostFlags->u32HostFlags & HGSMIHOSTFLAGS_COMMANDS_PENDING)
144 || commonFromDeviceExt(PrimaryExtension)->bHostCmdProcessing)
145 {
146 VBOX_HGSMI_UNLOCK(PrimaryExtension, &commonFromDeviceExt(PrimaryExtension)->pSynchLock, flags, OldIrql);
147 break;
148 }
149 Assert(!commonFromDeviceExt(PrimaryExtension)->bHostCmdProcessing);
150 commonFromDeviceExt(PrimaryExtension)->bHostCmdProcessing = true;
151 VBOX_HGSMI_UNLOCK(PrimaryExtension, &commonFromDeviceExt(PrimaryExtension)->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 < PrimaryExtension->u.primary.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 == PrimaryExtension->u.primary.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 (PDEVICE_EXTENSION PrimaryExtension)
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(commonFromDeviceExt(PrimaryExtension),
439 HGSMI_CH_HGSMI,
440 HGSMI_CC_HOST_FLAGS_LOCATION,
441 sizeof (HGSMIBUFFERLOCATION),
442 hgsmiInitFlagsLocation,
443 NULL,
444 NULL);
445 AssertRC(rc);
446#ifndef VBOX_WITH_WDDM
447 if (RT_SUCCESS(rc))
448 {
449 rc = VBoxHGSMISendViewInfo (commonFromDeviceExt(PrimaryExtension),
450 PrimaryExtension->u.primary.cDisplays,
451 vbvaInitInfoDisplay,
452 (void *) PrimaryExtension);
453 AssertRC(rc);
454 }
455 /* in case of WDDM we do not control the framebuffer location,
456 * i.e. it is assigned by Video Memory Manager,
457 * The FB information should be passed to guest from our
458 * DxgkDdiSetVidPnSourceAddress callback */
459#endif
460 if (RT_SUCCESS(rc) && commonFromDeviceExt(PrimaryExtension)->fCaps)
461 {
462 /* Inform about caps */
463 rc = vboxCallVBVA (commonFromDeviceExt(PrimaryExtension),
464 VBVA_INFO_CAPS,
465 sizeof (VBVACAPS),
466 vbvaInitInfoCaps,
467 vbvaFinalizeInfoCaps,
468 NULL);
469 AssertRC(rc);
470 }
471 if (RT_SUCCESS (rc))
472 {
473 /* Report the host heap location. */
474 rc = vboxCallVBVA (commonFromDeviceExt(PrimaryExtension),
475 VBVA_INFO_HEAP,
476 sizeof (VBVAINFOHEAP),
477 vbvaInitInfoHeap,
478 NULL,
479 NULL);
480 AssertRC(rc);
481 }
482
483
484 dprintf(("VBoxVideo::vboxSetupAdapterInfo finished rc = %d\n", rc));
485
486 return rc;
487}
488
489#ifndef VBOX_WITH_WDDM
490VP_STATUS vboxWaitForSingleObjectVoid(IN PVOID HwDeviceExtension, IN PVOID Object, IN PLARGE_INTEGER Timeout OPTIONAL)
491{
492 return ERROR_INVALID_FUNCTION;
493}
494
495LONG vboxSetEventVoid(IN PVOID HwDeviceExtension, IN PEVENT pEvent)
496{
497 return 0;
498}
499
500VOID vboxClearEventVoid (IN PVOID HwDeviceExtension, IN PEVENT pEvent)
501{
502}
503
504VP_STATUS vboxCreateEventVoid(IN PVOID HwDeviceExtension, IN ULONG EventFlag, IN PVOID Unused, OUT PEVENT *ppEvent)
505{
506 return ERROR_INVALID_FUNCTION;
507}
508
509VP_STATUS vboxDeleteEventVoid(IN PVOID HwDeviceExtension, IN PEVENT pEvent)
510{
511 return ERROR_INVALID_FUNCTION;
512}
513
514VP_STATUS vboxCreateSpinLockVoid (IN PVOID HwDeviceExtension, OUT PSPIN_LOCK *SpinLock)
515{
516 return ERROR_INVALID_FUNCTION;
517}
518
519VP_STATUS vboxDeleteSpinLockVoid (IN PVOID HwDeviceExtension, IN PSPIN_LOCK SpinLock)
520{
521 return ERROR_INVALID_FUNCTION;
522}
523
524VOID vboxAcquireSpinLockVoid (IN PVOID HwDeviceExtension, IN PSPIN_LOCK SpinLock, OUT PUCHAR OldIrql)
525{
526}
527
528VOID vboxReleaseSpinLockVoid (IN PVOID HwDeviceExtension, IN PSPIN_LOCK SpinLock, IN UCHAR NewIrql)
529{
530}
531
532VOID vboxAcquireSpinLockAtDpcLevelVoid (IN PVOID HwDeviceExtension, IN PSPIN_LOCK SpinLock)
533{
534}
535
536VOID vboxReleaseSpinLockFromDpcLevelVoid (IN PVOID HwDeviceExtension, IN PSPIN_LOCK SpinLock)
537{
538}
539
540PVOID vboxAllocatePoolVoid(IN PVOID HwDeviceExtension, IN VBOXVP_POOL_TYPE PoolType, IN size_t NumberOfBytes, IN ULONG Tag)
541{
542 return NULL;
543}
544
545VOID vboxFreePoolVoid(IN PVOID HwDeviceExtension, IN PVOID Ptr)
546{
547}
548
549BOOLEAN vboxQueueDpcVoid(IN PVOID HwDeviceExtension, IN PMINIPORT_DPC_ROUTINE CallbackRoutine, IN PVOID Context)
550{
551 return FALSE;
552}
553
554void VBoxSetupVideoPortFunctions(PDEVICE_EXTENSION PrimaryExtension, VBOXVIDEOPORTPROCS *pCallbacks, PVIDEO_PORT_CONFIG_INFO pConfigInfo)
555{
556 memset(pCallbacks, 0, sizeof(VBOXVIDEOPORTPROCS));
557
558 if (vboxQueryWinVersion() <= WINNT4)
559 {
560 /* VideoPortGetProcAddress is available for >= win2k */
561 pCallbacks->pfnWaitForSingleObject = vboxWaitForSingleObjectVoid;
562 pCallbacks->pfnSetEvent = vboxSetEventVoid;
563 pCallbacks->pfnClearEvent = vboxClearEventVoid;
564 pCallbacks->pfnCreateEvent = vboxCreateEventVoid;
565 pCallbacks->pfnDeleteEvent = vboxDeleteEventVoid;
566 pCallbacks->pfnCreateSpinLock = vboxCreateSpinLockVoid;
567 pCallbacks->pfnDeleteSpinLock = vboxDeleteSpinLockVoid;
568 pCallbacks->pfnAcquireSpinLock = vboxAcquireSpinLockVoid;
569 pCallbacks->pfnReleaseSpinLock = vboxReleaseSpinLockVoid;
570 pCallbacks->pfnAcquireSpinLockAtDpcLevel = vboxAcquireSpinLockAtDpcLevelVoid;
571 pCallbacks->pfnReleaseSpinLockFromDpcLevel = vboxReleaseSpinLockFromDpcLevelVoid;
572 pCallbacks->pfnAllocatePool = vboxAllocatePoolVoid;
573 pCallbacks->pfnFreePool = vboxFreePoolVoid;
574 pCallbacks->pfnQueueDpc = vboxQueueDpcVoid;
575 return;
576 }
577
578 pCallbacks->pfnWaitForSingleObject = (PFNWAITFORSINGLEOBJECT)(pConfigInfo->VideoPortGetProcAddress)
579 (PrimaryExtension,
580 (PUCHAR)"VideoPortWaitForSingleObject");
581 Assert(pCallbacks->pfnWaitForSingleObject);
582
583 pCallbacks->pfnSetEvent = (PFNSETEVENT)(pConfigInfo->VideoPortGetProcAddress)
584 (PrimaryExtension,
585 (PUCHAR)"VideoPortSetEvent");
586 Assert(pCallbacks->pfnSetEvent);
587
588 pCallbacks->pfnClearEvent = (PFNCLEAREVENT)(pConfigInfo->VideoPortGetProcAddress)
589 (PrimaryExtension,
590 (PUCHAR)"VideoPortClearEvent");
591 Assert(pCallbacks->pfnClearEvent);
592
593 pCallbacks->pfnCreateEvent = (PFNCREATEEVENT)(pConfigInfo->VideoPortGetProcAddress)
594 (PrimaryExtension,
595 (PUCHAR)"VideoPortCreateEvent");
596 Assert(pCallbacks->pfnCreateEvent);
597
598 pCallbacks->pfnDeleteEvent = (PFNDELETEEVENT)(pConfigInfo->VideoPortGetProcAddress)
599 (PrimaryExtension,
600 (PUCHAR)"VideoPortDeleteEvent");
601 Assert(pCallbacks->pfnDeleteEvent);
602
603 if(pCallbacks->pfnWaitForSingleObject
604 && pCallbacks->pfnSetEvent
605 && pCallbacks->pfnClearEvent
606 && pCallbacks->pfnCreateEvent
607 && pCallbacks->pfnDeleteEvent)
608 {
609 pCallbacks->fSupportedTypes |= VBOXVIDEOPORTPROCS_EVENT;
610 }
611 else
612 {
613 pCallbacks->pfnWaitForSingleObject = vboxWaitForSingleObjectVoid;
614 pCallbacks->pfnSetEvent = vboxSetEventVoid;
615 pCallbacks->pfnClearEvent = vboxClearEventVoid;
616 pCallbacks->pfnCreateEvent = vboxCreateEventVoid;
617 pCallbacks->pfnDeleteEvent = vboxDeleteEventVoid;
618 }
619
620 pCallbacks->pfnCreateSpinLock = (PFNCREATESPINLOCK)(pConfigInfo->VideoPortGetProcAddress)
621 (PrimaryExtension,
622 (PUCHAR)"VideoPortCreateSpinLock");
623 Assert(pCallbacks->pfnCreateSpinLock);
624
625 pCallbacks->pfnDeleteSpinLock = (PFNDELETESPINLOCK)(pConfigInfo->VideoPortGetProcAddress)
626 (PrimaryExtension,
627 (PUCHAR)"VideoPortDeleteSpinLock");
628 Assert(pCallbacks->pfnDeleteSpinLock);
629
630 pCallbacks->pfnAcquireSpinLock = (PFNACQUIRESPINLOCK)(pConfigInfo->VideoPortGetProcAddress)
631 (PrimaryExtension,
632 (PUCHAR)"VideoPortAcquireSpinLock");
633 Assert(pCallbacks->pfnAcquireSpinLock);
634
635 pCallbacks->pfnReleaseSpinLock = (PFNRELEASESPINLOCK)(pConfigInfo->VideoPortGetProcAddress)
636 (PrimaryExtension,
637 (PUCHAR)"VideoPortReleaseSpinLock");
638 Assert(pCallbacks->pfnReleaseSpinLock);
639
640 pCallbacks->pfnAcquireSpinLockAtDpcLevel = (PFNACQUIRESPINLOCKATDPCLEVEL)(pConfigInfo->VideoPortGetProcAddress)
641 (PrimaryExtension,
642 (PUCHAR)"VideoPortAcquireSpinLockAtDpcLevel");
643 Assert(pCallbacks->pfnAcquireSpinLockAtDpcLevel);
644
645 pCallbacks->pfnReleaseSpinLockFromDpcLevel = (PFNRELEASESPINLOCKFROMDPCLEVEL)(pConfigInfo->VideoPortGetProcAddress)
646 (PrimaryExtension,
647 (PUCHAR)"VideoPortReleaseSpinLockFromDpcLevel");
648 Assert(pCallbacks->pfnReleaseSpinLockFromDpcLevel);
649
650 if(pCallbacks->pfnCreateSpinLock
651 && pCallbacks->pfnDeleteSpinLock
652 && pCallbacks->pfnAcquireSpinLock
653 && pCallbacks->pfnReleaseSpinLock
654 && pCallbacks->pfnAcquireSpinLockAtDpcLevel
655 && pCallbacks->pfnReleaseSpinLockFromDpcLevel)
656 {
657 pCallbacks->fSupportedTypes |= VBOXVIDEOPORTPROCS_SPINLOCK;
658 }
659 else
660 {
661 pCallbacks->pfnCreateSpinLock = vboxCreateSpinLockVoid;
662 pCallbacks->pfnDeleteSpinLock = vboxDeleteSpinLockVoid;
663 pCallbacks->pfnAcquireSpinLock = vboxAcquireSpinLockVoid;
664 pCallbacks->pfnReleaseSpinLock = vboxReleaseSpinLockVoid;
665 pCallbacks->pfnAcquireSpinLockAtDpcLevel = vboxAcquireSpinLockAtDpcLevelVoid;
666 pCallbacks->pfnReleaseSpinLockFromDpcLevel = vboxReleaseSpinLockFromDpcLevelVoid;
667 }
668
669 pCallbacks->pfnAllocatePool = (PFNALLOCATEPOOL)(pConfigInfo->VideoPortGetProcAddress)
670 (PrimaryExtension,
671 (PUCHAR)"VideoPortAllocatePool");
672 Assert(pCallbacks->pfnAllocatePool);
673
674 pCallbacks->pfnFreePool = (PFNFREEPOOL)(pConfigInfo->VideoPortGetProcAddress)
675 (PrimaryExtension,
676 (PUCHAR)"VideoPortFreePool");
677 Assert(pCallbacks->pfnFreePool);
678
679 if(pCallbacks->pfnAllocatePool
680 && pCallbacks->pfnFreePool)
681 {
682 pCallbacks->fSupportedTypes |= VBOXVIDEOPORTPROCS_POOL;
683 }
684 else
685 {
686 pCallbacks->pfnAllocatePool = vboxAllocatePoolVoid;
687 pCallbacks->pfnFreePool = vboxFreePoolVoid;
688 }
689
690 pCallbacks->pfnQueueDpc = (PFNQUEUEDPC)(pConfigInfo->VideoPortGetProcAddress)
691 (PrimaryExtension,
692 (PUCHAR)"VideoPortQueueDpc");
693 Assert(pCallbacks->pfnQueueDpc);
694
695 if(pCallbacks->pfnQueueDpc)
696 {
697 pCallbacks->fSupportedTypes |= VBOXVIDEOPORTPROCS_DPC;
698 }
699 else
700 {
701 pCallbacks->pfnQueueDpc = vboxQueueDpcVoid;
702 }
703
704#ifdef DEBUG_misha
705 Assert(pCallbacks->fSupportedTypes & VBOXVIDEOPORTPROCS_EVENT);
706 Assert(pCallbacks->fSupportedTypes & VBOXVIDEOPORTPROCS_SPINLOCK);
707#endif
708}
709#endif
710
711/**
712 * Helper function to register secondary displays (DualView). Note that this will not
713 * be available on pre-XP versions, and some editions on XP will fail because they are
714 * intentionally crippled.
715 *
716 * HGSMI variant is a bit different because it uses only HGSMI interface (VBVA channel)
717 * to talk to the host.
718 */
719VOID VBoxSetupDisplaysHGSMI(PDEVICE_EXTENSION PrimaryExtension,
720#ifndef VBOX_WITH_WDDM
721 PVIDEO_PORT_CONFIG_INFO pConfigInfo,
722#endif
723 ULONG AdapterMemorySize, uint32_t fCaps)
724{
725 VP_STATUS rc = NO_ERROR;
726
727 dprintf(("VBoxVideo::VBoxSetupDisplays: PrimaryExtension = %p\n",
728 PrimaryExtension));
729
730 memset(commonFromDeviceExt(PrimaryExtension), 0,
731 sizeof(*commonFromDeviceExt(PrimaryExtension)));
732 commonFromDeviceExt(PrimaryExtension)->cbVRAM = AdapterMemorySize;
733 commonFromDeviceExt(PrimaryExtension)->fCaps = fCaps;
734 commonFromDeviceExt(PrimaryExtension)->bHGSMI = VBoxHGSMIIsSupported ();
735 /* Why does this use VBoxVideoCmnMemZero? The MSDN docs say that it should
736 * only be used on mapped display adapter memory. Done with memset above. */
737 // VBoxVideoCmnMemZero(&commonFromDeviceExt(PrimaryExtension)->areaHostHeap, sizeof(HGSMIAREA));
738 if (commonFromDeviceExt(PrimaryExtension)->bHGSMI)
739 {
740 /** @note (michael) moved this here as it is done unconditionally in both
741 * driver branches. Feel free to fix if that is ever changed. */
742 commonFromDeviceExt(PrimaryExtension)->IOPortHost = (RTIOPORT)VGA_PORT_HGSMI_HOST;
743 commonFromDeviceExt(PrimaryExtension)->IOPortGuest = (RTIOPORT)VGA_PORT_HGSMI_GUEST;
744
745 /* Map the adapter information. It will be needed for HGSMI IO. */
746 rc = VBoxMapAdapterMemory (commonFromDeviceExt(PrimaryExtension),
747 &commonFromDeviceExt(PrimaryExtension)->pvAdapterInformation,
748 AdapterMemorySize - VBVA_ADAPTER_INFORMATION_SIZE,
749 VBVA_ADAPTER_INFORMATION_SIZE
750 );
751 if (rc != NO_ERROR)
752 {
753 dprintf(("VBoxVideo::VBoxSetupDisplays: VBoxMapAdapterMemory pvAdapterInfoirrmation failed rc = %d\n",
754 rc));
755
756 commonFromDeviceExt(PrimaryExtension)->bHGSMI = FALSE;
757 }
758 else
759 {
760 /* Setup a HGSMI heap within the adapter information area. */
761 rc = HGSMIHeapSetup (&commonFromDeviceExt(PrimaryExtension)->hgsmiAdapterHeap,
762 commonFromDeviceExt(PrimaryExtension)->pvAdapterInformation,
763 VBVA_ADAPTER_INFORMATION_SIZE - sizeof(HGSMIHOSTFLAGS),
764 commonFromDeviceExt(PrimaryExtension)->cbVRAM - VBVA_ADAPTER_INFORMATION_SIZE,
765 false /*fOffsetBased*/);
766
767 if (RT_FAILURE (rc))
768 {
769 dprintf(("VBoxVideo::VBoxSetupDisplays: HGSMIHeapSetup failed rc = %d\n",
770 rc));
771
772 commonFromDeviceExt(PrimaryExtension)->bHGSMI = FALSE;
773 }
774 else
775 {
776 commonFromDeviceExt(PrimaryExtension)->pHostFlags = (HGSMIHOSTFLAGS*)(((uint8_t*)commonFromDeviceExt(PrimaryExtension)->pvAdapterInformation)
777 + VBVA_ADAPTER_INFORMATION_SIZE - sizeof(HGSMIHOSTFLAGS));
778 }
779 }
780 }
781
782 /* Setup the host heap and the adapter memory. */
783 if (commonFromDeviceExt(PrimaryExtension)->bHGSMI)
784 {
785 /* The miniport heap is used for the host buffers. */
786 ULONG cbMiniportHeap = 0;
787 vboxQueryConfHGSMI (commonFromDeviceExt(PrimaryExtension), VBOX_VBVA_CONF32_HOST_HEAP_SIZE, &cbMiniportHeap);
788
789 if (cbMiniportHeap != 0)
790 {
791 /* Do not allow too big heap. No more than 25% of VRAM is allowed. */
792 ULONG cbMiniportHeapMaxSize = AdapterMemorySize / 4;
793
794 if (cbMiniportHeapMaxSize >= VBVA_ADAPTER_INFORMATION_SIZE)
795 {
796 cbMiniportHeapMaxSize -= VBVA_ADAPTER_INFORMATION_SIZE;
797 }
798
799 if (cbMiniportHeap > cbMiniportHeapMaxSize)
800 {
801 cbMiniportHeap = cbMiniportHeapMaxSize;
802 }
803
804 /* Round up to 4096 bytes. */
805 commonFromDeviceExt(PrimaryExtension)->cbMiniportHeap = (cbMiniportHeap + 0xFFF) & ~0xFFF;
806
807 dprintf(("VBoxVideo::VBoxSetupDisplays: cbMiniportHeap = 0x%08X, PrimaryExtension->u.primary.cbMiniportHeap = 0x%08X, cbMiniportHeapMaxSize = 0x%08X\n",
808 cbMiniportHeap, commonFromDeviceExt(PrimaryExtension)->cbMiniportHeap, cbMiniportHeapMaxSize));
809
810 /* Map the heap region.
811 *
812 * Note: the heap will be used for the host buffers submitted to the guest.
813 * The miniport driver is responsible for reading FIFO and notifying
814 * display drivers.
815 */
816 rc = VBoxMapAdapterMemory (commonFromDeviceExt(PrimaryExtension),
817 &commonFromDeviceExt(PrimaryExtension)->pvMiniportHeap,
818 commonFromDeviceExt(PrimaryExtension)->cbVRAM
819 - VBVA_ADAPTER_INFORMATION_SIZE
820 - commonFromDeviceExt(PrimaryExtension)->cbMiniportHeap,
821 commonFromDeviceExt(PrimaryExtension)->cbMiniportHeap
822 );
823 if (rc != NO_ERROR)
824 {
825 commonFromDeviceExt(PrimaryExtension)->pvMiniportHeap = NULL;
826 commonFromDeviceExt(PrimaryExtension)->cbMiniportHeap = 0;
827 commonFromDeviceExt(PrimaryExtension)->bHGSMI = FALSE;
828 }
829 else
830 {
831 HGSMIOFFSET offBase = commonFromDeviceExt(PrimaryExtension)->cbVRAM
832 - VBVA_ADAPTER_INFORMATION_SIZE
833 - commonFromDeviceExt(PrimaryExtension)->cbMiniportHeap;
834
835 /* Init the host hap area. Buffers from the host will be placed there. */
836 HGSMIAreaInitialize (&commonFromDeviceExt(PrimaryExtension)->areaHostHeap,
837 commonFromDeviceExt(PrimaryExtension)->pvMiniportHeap,
838 commonFromDeviceExt(PrimaryExtension)->cbMiniportHeap,
839 offBase);
840 }
841 }
842 else
843 {
844 /* Host has not requested a heap. */
845 commonFromDeviceExt(PrimaryExtension)->pvMiniportHeap = NULL;
846 commonFromDeviceExt(PrimaryExtension)->cbMiniportHeap = 0;
847 }
848 }
849
850 /* Check whether the guest supports multimonitors. */
851 if (commonFromDeviceExt(PrimaryExtension)->bHGSMI)
852 {
853#ifndef VBOX_WITH_WDDM
854 typedef VP_STATUS (*PFNCREATESECONDARYDISPLAY)(PVOID, PVOID *, ULONG);
855 PFNCREATESECONDARYDISPLAY pfnCreateSecondaryDisplay = NULL;
856
857 /* Dynamically query the VideoPort import to be binary compatible across Windows versions */
858 if (vboxQueryWinVersion() > WINNT4)
859 {
860 /* This bluescreens on NT4, hence the above version check */
861 pfnCreateSecondaryDisplay = (PFNCREATESECONDARYDISPLAY)(pConfigInfo->VideoPortGetProcAddress)
862 (PrimaryExtension,
863 (PUCHAR)"VideoPortCreateSecondaryDisplay");
864 }
865
866 if (pfnCreateSecondaryDisplay != NULL)
867#endif
868 {
869 /* Query the configured number of displays. */
870 ULONG cDisplays = 0;
871 vboxQueryConfHGSMI (commonFromDeviceExt(PrimaryExtension), VBOX_VBVA_CONF32_MONITOR_COUNT, &cDisplays);
872
873 dprintf(("VBoxVideo::VBoxSetupDisplays: cDisplays = %d\n",
874 cDisplays));
875
876 if (cDisplays == 0 || cDisplays > VBOX_VIDEO_MAX_SCREENS)
877 {
878 /* Host reported some bad value. Continue in the 1 screen mode. */
879 cDisplays = 1;
880 }
881
882#ifndef VBOX_WITH_WDDM
883 PDEVICE_EXTENSION pPrev = PrimaryExtension;
884
885 ULONG iDisplay;
886 for (iDisplay = 1; iDisplay < cDisplays; iDisplay++)
887 {
888 PDEVICE_EXTENSION SecondaryExtension = NULL;
889 rc = pfnCreateSecondaryDisplay (PrimaryExtension, (PVOID*)&SecondaryExtension, VIDEO_DUALVIEW_REMOVABLE);
890
891 dprintf(("VBoxVideo::VBoxSetupDisplays: VideoPortCreateSecondaryDisplay returned %#x, SecondaryExtension = %p\n",
892 rc, SecondaryExtension));
893
894 if (rc != NO_ERROR)
895 {
896 break;
897 }
898
899 SecondaryExtension->pNext = NULL;
900 SecondaryExtension->pPrimary = PrimaryExtension;
901 SecondaryExtension->iDevice = iDisplay;
902 SecondaryExtension->ulFrameBufferOffset = 0;
903 SecondaryExtension->ulFrameBufferSize = 0;
904 SecondaryExtension->u.secondary.bEnabled = FALSE;
905
906 /* Update the list pointers. */
907 pPrev->pNext = SecondaryExtension;
908 pPrev = SecondaryExtension;
909
910 /* Take the successfully created display into account. */
911 PrimaryExtension->u.primary.cDisplays++;
912 }
913#else
914 /* simply store the number of monitors, we will deal with VidPN stuff later */
915 PrimaryExtension->u.primary.cDisplays = cDisplays;
916#endif
917 }
918
919 /* Failure to create secondary displays is not fatal */
920 rc = NO_ERROR;
921 }
922
923#ifndef VBOX_WITH_WDDM
924 /* Now when the number of monitors is known and extensions are created,
925 * calculate the layout of framebuffers.
926 */
927 VBoxComputeFrameBufferSizes (PrimaryExtension);
928#endif
929
930 if (commonFromDeviceExt(PrimaryExtension)->bHGSMI)
931 {
932 /* Setup the information for the host. */
933 rc = vboxSetupAdapterInfoHGSMI (PrimaryExtension);
934
935 if (RT_FAILURE (rc))
936 {
937 commonFromDeviceExt(PrimaryExtension)->bHGSMI = FALSE;
938 }
939 }
940
941#ifdef VBOX_WITH_WDDM
942 if (commonFromDeviceExt(PrimaryExtension)->bHGSMI)
943 {
944 ULONG ulAvailable = commonFromDeviceExt(PrimaryExtension)->cbVRAM
945 - commonFromDeviceExt(PrimaryExtension)->cbMiniportHeap
946 - VBVA_ADAPTER_INFORMATION_SIZE;
947
948 ULONG ulSize;
949 ULONG offset;
950#ifdef VBOX_WITH_VDMA
951 ulSize = ulAvailable / 2;
952 if (ulSize > VBOXWDDM_C_VDMA_BUFFER_SIZE)
953 ulSize = VBOXWDDM_C_VDMA_BUFFER_SIZE;
954
955 /* Align down to 4096 bytes. */
956 ulSize &= ~0xFFF;
957 offset = ulAvailable - ulSize;
958
959 Assert(!(offset & 0xFFF));
960#else
961 offset = ulAvailable;
962#endif
963 rc = vboxVdmaCreate (PrimaryExtension, &PrimaryExtension->u.primary.Vdma
964#ifdef VBOX_WITH_VDMA
965 , offset, ulSize
966#endif
967 );
968 AssertRC(rc);
969 if (RT_SUCCESS(rc))
970 {
971 /* can enable it right away since the host does not need any screen/FB info
972 * for basic DMA functionality */
973 rc = vboxVdmaEnable(PrimaryExtension, &PrimaryExtension->u.primary.Vdma);
974 AssertRC(rc);
975 if (RT_FAILURE(rc))
976 vboxVdmaDestroy(PrimaryExtension, &PrimaryExtension->u.primary.Vdma);
977 }
978
979#ifdef VBOXWDDM_RENDER_FROM_SHADOW
980 if (RT_SUCCESS(rc))
981 {
982 ulAvailable = offset;
983 ulSize = ulAvailable / 2;
984 ulSize /= PrimaryExtension->u.primary.cDisplays;
985 Assert(ulSize > VBVA_MIN_BUFFER_SIZE);
986 if (ulSize > VBVA_MIN_BUFFER_SIZE)
987 {
988 ULONG ulRatio = ulSize/VBVA_MIN_BUFFER_SIZE;
989 ulRatio >>= 4; /* /= 16; */
990 if (ulRatio)
991 ulSize = VBVA_MIN_BUFFER_SIZE * ulRatio;
992 else
993 ulSize = VBVA_MIN_BUFFER_SIZE;
994 }
995 else
996 {
997 /* todo: ?? */
998 }
999
1000 ulSize &= ~0xFFF;
1001 Assert(ulSize);
1002
1003 Assert(ulSize * PrimaryExtension->u.primary.cDisplays < ulAvailable);
1004
1005 for (int i = PrimaryExtension->u.primary.cDisplays-1; i >= 0; --i)
1006 {
1007 offset -= ulSize;
1008 rc = vboxVbvaCreate(PrimaryExtension, &PrimaryExtension->aSources[i].Vbva, offset, ulSize, i);
1009 AssertRC(rc);
1010 if (RT_SUCCESS(rc))
1011 {
1012 rc = vboxVbvaEnable(PrimaryExtension, &PrimaryExtension->aSources[i].Vbva);
1013 AssertRC(rc);
1014 if (RT_FAILURE(rc))
1015 {
1016 /* @todo: de-initialize */
1017 }
1018 }
1019 }
1020 }
1021#endif
1022
1023 rc = VBoxMapAdapterMemory(commonFromDeviceExt(PrimaryExtension), (void**)&PrimaryExtension->pvVisibleVram,
1024 0,
1025 vboxWddmVramCpuVisibleSize(PrimaryExtension));
1026 Assert(rc == VINF_SUCCESS);
1027 if (rc != VINF_SUCCESS)
1028 PrimaryExtension->pvVisibleVram = NULL;
1029
1030 if (RT_FAILURE(rc))
1031 commonFromDeviceExt(PrimaryExtension)->bHGSMI = FALSE;
1032 }
1033#endif
1034
1035 if (!commonFromDeviceExt(PrimaryExtension)->bHGSMI)
1036 {
1037 /* Unmap the memory if VBoxVideo is not supported. */
1038 VBoxUnmapAdapterMemory (PrimaryExtension, &commonFromDeviceExt(PrimaryExtension)->pvMiniportHeap, commonFromDeviceExt(PrimaryExtension)->cbMiniportHeap);
1039 VBoxUnmapAdapterInformation (PrimaryExtension);
1040
1041 HGSMIHeapDestroy (&commonFromDeviceExt(PrimaryExtension)->hgsmiAdapterHeap);
1042 }
1043
1044 if (commonFromDeviceExt(PrimaryExtension)->bHGSMI)
1045 {
1046 VBoxVideoCmnSpinLockCreate(PrimaryExtension, &commonFromDeviceExt(PrimaryExtension)->pSynchLock);
1047 }
1048
1049 dprintf(("VBoxVideo::VBoxSetupDisplays: finished\n"));
1050}
1051
1052#ifdef VBOX_WITH_WDDM
1053int VBoxFreeDisplaysHGSMI(PDEVICE_EXTENSION PrimaryExtension)
1054{
1055 int rc = VINF_SUCCESS;
1056
1057 Assert(PrimaryExtension->pvVisibleVram);
1058 if (PrimaryExtension->pvVisibleVram)
1059 VBoxUnmapAdapterMemory(PrimaryExtension, (void**)&PrimaryExtension->pvVisibleVram, vboxWddmVramCpuVisibleSize(PrimaryExtension));
1060
1061 for (int i = PrimaryExtension->u.primary.cDisplays-1; i >= 0; --i)
1062 {
1063 rc = vboxVbvaDisable(PrimaryExtension, &PrimaryExtension->aSources[i].Vbva);
1064 AssertRC(rc);
1065 if (RT_SUCCESS(rc))
1066 {
1067 rc = vboxVbvaDestroy(PrimaryExtension, &PrimaryExtension->aSources[i].Vbva);
1068 AssertRC(rc);
1069 if (RT_FAILURE(rc))
1070 {
1071 /* @todo: */
1072 }
1073 }
1074 }
1075
1076 rc = vboxVdmaDisable(PrimaryExtension, &PrimaryExtension->u.primary.Vdma);
1077 AssertRC(rc);
1078 if (RT_SUCCESS(rc))
1079 {
1080 rc = vboxVdmaDestroy(PrimaryExtension, &PrimaryExtension->u.primary.Vdma);
1081 AssertRC(rc);
1082 if (RT_SUCCESS(rc))
1083 {
1084 /*rc = */VBoxUnmapAdapterMemory(PrimaryExtension, &commonFromDeviceExt(PrimaryExtension)->pvMiniportHeap, commonFromDeviceExt(PrimaryExtension)->cbMiniportHeap);
1085/*
1086 AssertRC(rc);
1087 if (RT_SUCCESS(rc))
1088*/
1089 {
1090 HGSMIHeapDestroy(&commonFromDeviceExt(PrimaryExtension)->hgsmiAdapterHeap);
1091
1092 /* Map the adapter information. It will be needed for HGSMI IO. */
1093 /*rc = */VBoxUnmapAdapterInformation(PrimaryExtension);
1094/*
1095 AssertRC(rc);
1096 if (RT_FAILURE(rc))
1097 drprintf((__FUNCTION__"VBoxUnmapAdapterMemory PrimaryExtension->u.primary.pvAdapterInformation failed, rc(%d)\n", rc));
1098*/
1099
1100 }
1101 }
1102 }
1103
1104 return rc;
1105}
1106#endif
1107
1108/*
1109 * Send the pointer shape to the host.
1110 */
1111typedef struct _MOUSEPOINTERSHAPECTX
1112{
1113 VIDEO_POINTER_ATTRIBUTES *pPointerAttr;
1114 uint32_t cbData;
1115 int32_t i32Result;
1116} MOUSEPOINTERSHAPECTX;
1117
1118static int vbvaInitMousePointerShape (PVBOXVIDEO_COMMON, void *pvContext, void *pvData)
1119{
1120 MOUSEPOINTERSHAPECTX *pCtx = (MOUSEPOINTERSHAPECTX *)pvContext;
1121 VBVAMOUSEPOINTERSHAPE *p = (VBVAMOUSEPOINTERSHAPE *)pvData;
1122
1123 /* Will be updated by the host. */
1124 p->i32Result = VINF_SUCCESS;
1125
1126 /* We have our custom flags in the field */
1127 p->fu32Flags = pCtx->pPointerAttr->Enable & 0x0000FFFF;
1128
1129 p->u32HotX = (pCtx->pPointerAttr->Enable >> 16) & 0xFF;
1130 p->u32HotY = (pCtx->pPointerAttr->Enable >> 24) & 0xFF;
1131 p->u32Width = pCtx->pPointerAttr->Width;
1132 p->u32Height = pCtx->pPointerAttr->Height;
1133
1134 if (p->fu32Flags & VBOX_MOUSE_POINTER_SHAPE)
1135 {
1136 /* If shape is supplied, then alway create the pointer visible.
1137 * See comments in 'vboxUpdatePointerShape'
1138 */
1139 p->fu32Flags |= VBOX_MOUSE_POINTER_VISIBLE;
1140
1141 /* Copy the actual pointer data. */
1142 memcpy (p->au8Data, pCtx->pPointerAttr->Pixels, pCtx->cbData);
1143 }
1144
1145 return VINF_SUCCESS;
1146}
1147
1148static int vbvaFinalizeMousePointerShape (PVBOXVIDEO_COMMON, void *pvContext, void *pvData)
1149{
1150 MOUSEPOINTERSHAPECTX *pCtx = (MOUSEPOINTERSHAPECTX *)pvContext;
1151 VBVAMOUSEPOINTERSHAPE *p = (VBVAMOUSEPOINTERSHAPE *)pvData;
1152
1153 pCtx->i32Result = p->i32Result;
1154
1155 return VINF_SUCCESS;
1156}
1157
1158BOOLEAN vboxUpdatePointerShape (PDEVICE_EXTENSION DeviceExtension,
1159 PVIDEO_POINTER_ATTRIBUTES pointerAttr,
1160 uint32_t cbLength)
1161{
1162#ifndef VBOX_WITH_WDDM
1163 PDEVICE_EXTENSION PrimaryExtension = DeviceExtension->pPrimary;
1164
1165 /* In multimonitor case the HW mouse pointer is the same on all screens,
1166 * and Windows calls each display driver with the same pointer data: visible for
1167 * the screen where the pointer is and invisible for other screens.
1168 *
1169 * This driver passes the shape to the host only from primary screen and makes
1170 * the pointer always visible (in vbvaInitMousePointerShape).
1171 *
1172 * The simple solution makes it impossible to create the shape and keep the mouse
1173 * pointer invisible. New shapes will be created visible.
1174 * But:
1175 * 1) VBox frontends actually ignore the visibility flag if VBOX_MOUSE_POINTER_SHAPE
1176 * is set and always create new pointers visible.
1177 * 2) Windows uses DrvMovePointer to hide the pointer, which will still work.
1178 */
1179
1180 if (DeviceExtension->iDevice != PrimaryExtension->iDevice)
1181 {
1182 dprintf(("vboxUpdatePointerShape: ignore non primary device %d(%d)\n",
1183 DeviceExtension->iDevice, PrimaryExtension->iDevice));
1184 /* Success. */
1185 return TRUE;
1186 }
1187#else
1188 PDEVICE_EXTENSION PrimaryExtension = DeviceExtension;
1189#endif
1190
1191 uint32_t cbData = 0;
1192
1193 if (pointerAttr->Enable & VBOX_MOUSE_POINTER_SHAPE)
1194 {
1195 /* Size of the pointer data: sizeof (AND mask) + sizeof (XOR_MASK) */
1196 cbData = ((((pointerAttr->Width + 7) / 8) * pointerAttr->Height + 3) & ~3)
1197 + pointerAttr->Width * 4 * pointerAttr->Height;
1198 }
1199
1200#ifndef DEBUG_misha
1201 dprintf(("vboxUpdatePointerShape: cbData %d, %dx%d\n",
1202 cbData, pointerAttr->Width, pointerAttr->Height));
1203#endif
1204
1205 if (cbData > cbLength - sizeof(VIDEO_POINTER_ATTRIBUTES))
1206 {
1207 dprintf(("vboxUpdatePointerShape: calculated pointer data size is too big (%d bytes, limit %d)\n",
1208 cbData, cbLength - sizeof(VIDEO_POINTER_ATTRIBUTES)));
1209 return FALSE;
1210 }
1211
1212 MOUSEPOINTERSHAPECTX ctx;
1213
1214 ctx.pPointerAttr = pointerAttr;
1215 ctx.cbData = cbData;
1216 ctx.i32Result = VERR_NOT_SUPPORTED;
1217
1218 int rc = vboxCallVBVA (commonFromDeviceExt(PrimaryExtension),
1219 VBVA_MOUSE_POINTER_SHAPE,
1220 sizeof (VBVAMOUSEPOINTERSHAPE) + cbData,
1221 vbvaInitMousePointerShape,
1222 vbvaFinalizeMousePointerShape,
1223 &ctx);
1224#ifndef DEBUG_misha
1225 dprintf(("VBoxVideo::vboxMousePointerShape: rc %d, i32Result = %d\n", rc, ctx.i32Result));
1226#endif
1227
1228 return RT_SUCCESS(rc) && RT_SUCCESS(ctx.i32Result);
1229}
1230
1231#ifndef VBOX_WITH_WDDM
1232typedef struct _VBVAMINIPORT_CHANNELCONTEXT
1233{
1234 PFNHGSMICHANNELHANDLER pfnChannelHandler;
1235 void *pvChannelHandler;
1236}VBVAMINIPORT_CHANNELCONTEXT;
1237
1238typedef struct _VBVADISP_CHANNELCONTEXT
1239{
1240 struct _VBVAHOSTCMD * pFirstCmd;
1241 struct _VBVAHOSTCMD * pLastCmd;
1242 VBOXVCMNSPIN_LOCK pSynchLock;
1243#ifdef DEBUG
1244 int cCmds;
1245#endif
1246 bool bValid;
1247}VBVADISP_CHANNELCONTEXT;
1248
1249#ifdef DEBUG
1250void dbgCheckListLocked(const VBVADISP_CHANNELCONTEXT *pList, struct _VBVAHOSTCMD * pCmd)
1251{
1252 int counter = 0;
1253 for(struct _VBVAHOSTCMD * pCur = pList->pFirstCmd; pCur; pCur=pCur->u.pNext)
1254 {
1255 Assert(pCur != pCmd);
1256 if(pCur == pList->pLastCmd)
1257 {
1258 Assert(pCur->u.pNext == NULL);
1259 }
1260 if(pCur->u.pNext == NULL)
1261 {
1262 Assert(pCur == pList->pLastCmd);
1263 }
1264 counter++;
1265 }
1266
1267 Assert(counter == pList->cCmds);
1268}
1269
1270void dbgCheckList(PDEVICE_EXTENSION PrimaryExtension, VBVADISP_CHANNELCONTEXT *pList, struct _VBVAHOSTCMD * pCmd)
1271{
1272 VBOXVCMNIRQL oldIrql;
1273 VBoxVideoCmnSpinLockAcquire(PrimaryExtension, &pList->pSynchLock, &oldIrql);
1274
1275 dbgCheckListLocked(pList, pCmd);
1276
1277 VBoxVideoCmnSpinLockRelease(PrimaryExtension, &pList->pSynchLock, oldIrql);
1278}
1279
1280#define DBG_CHECKLIST_LOCKED(_pl, pc) dbgCheckListLocked(_pl, pc)
1281#define DBG_CHECKLIST(_pe, _pl, pc) dbgCheckList(_pe, _pl, pc)
1282
1283#else
1284#define DBG_CHECKLIST_LOCKED(_pl, pc) do{}while(0)
1285#define DBG_CHECKLIST(_pe, _pl, pc) do{}while(0)
1286#endif
1287
1288
1289typedef struct _VBVA_CHANNELCONTEXTS
1290{
1291 PDEVICE_EXTENSION PrimaryExtension;
1292 uint32_t cUsed;
1293 uint32_t cContexts;
1294 VBVAMINIPORT_CHANNELCONTEXT mpContext;
1295 VBVADISP_CHANNELCONTEXT aContexts[1];
1296}VBVA_CHANNELCONTEXTS;
1297
1298static int vboxVBVADeleteChannelContexts(PDEVICE_EXTENSION PrimaryExtension, VBVA_CHANNELCONTEXTS * pContext)
1299{
1300 VBoxVideoCmnMemFree(PrimaryExtension,pContext);
1301 return VINF_SUCCESS;
1302}
1303
1304static int vboxVBVACreateChannelContexts(PDEVICE_EXTENSION PrimaryExtension, VBVA_CHANNELCONTEXTS ** ppContext)
1305{
1306#ifndef VBOX_WITH_WDDM
1307 uint32_t cDisplays = (uint32_t)PrimaryExtension->u.primary.cDisplays;
1308#else
1309 uint32_t cDisplays = (uint32_t)PrimaryExtension->u.primary.cDisplays;
1310#endif
1311 const size_t size = RT_OFFSETOF(VBVA_CHANNELCONTEXTS, aContexts[cDisplays]);
1312 VBVA_CHANNELCONTEXTS * pContext = (VBVA_CHANNELCONTEXTS*)VBoxVideoCmnMemAllocNonPaged(PrimaryExtension, size, MEM_TAG);
1313 if(pContext)
1314 {
1315 memset(pContext, 0, size);
1316 pContext->cContexts = cDisplays;
1317 pContext->PrimaryExtension = PrimaryExtension;
1318 *ppContext = pContext;
1319 return VINF_SUCCESS;
1320 }
1321 return VERR_GENERAL_FAILURE;
1322}
1323
1324static VBVADISP_CHANNELCONTEXT* vboxVBVAFindHandlerInfo(VBVA_CHANNELCONTEXTS *pCallbacks, int iId)
1325{
1326 if(iId < 0)
1327 {
1328 return NULL;
1329 }
1330 else if(pCallbacks->cContexts > (uint32_t)iId)
1331 {
1332 return &pCallbacks->aContexts[iId];
1333 }
1334 return NULL;
1335}
1336
1337DECLCALLBACK(void) hgsmiHostCmdComplete (HVBOXVIDEOHGSMI hHGSMI, struct _VBVAHOSTCMD * pCmd)
1338{
1339 PDEVICE_EXTENSION PrimaryExtension = ((PDEVICE_EXTENSION)hHGSMI)->pPrimary;
1340 HGSMIHostCmdComplete (commonFromDeviceExt(PrimaryExtension), pCmd);
1341}
1342
1343DECLCALLBACK(int) hgsmiHostCmdRequest (HVBOXVIDEOHGSMI hHGSMI, uint8_t u8Channel, struct _VBVAHOSTCMD ** ppCmd)
1344{
1345// if(display < 0)
1346// return VERR_INVALID_PARAMETER;
1347 if(!ppCmd)
1348 return VERR_INVALID_PARAMETER;
1349
1350 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)hHGSMI;
1351 PDEVICE_EXTENSION PrimaryExtension = pDevExt->pPrimary;
1352
1353 /* pick up the host commands */
1354 VBoxVideoHGSMIDpc(PrimaryExtension, NULL);
1355
1356 HGSMICHANNEL * pChannel = HGSMIChannelFindById (&commonFromDeviceExt(PrimaryExtension)->channels, u8Channel);
1357 if(pChannel)
1358 {
1359 VBVA_CHANNELCONTEXTS * pContexts = (VBVA_CHANNELCONTEXTS *)pChannel->handler.pvHandler;
1360 VBVADISP_CHANNELCONTEXT *pDispContext = vboxVBVAFindHandlerInfo(pContexts, pDevExt->iDevice);
1361 Assert(pDispContext);
1362 if(pDispContext)
1363 {
1364 UCHAR oldIrql;
1365 VBoxVideoCmnSpinLockAcquire(PrimaryExtension, &pDispContext->pSynchLock, &oldIrql);
1366
1367 DBG_CHECKLIST_LOCKED(pDispContext, NULL);
1368
1369 *ppCmd = pDispContext->pFirstCmd;
1370 pDispContext->pFirstCmd = NULL;
1371 pDispContext->pLastCmd = NULL;
1372#ifdef DEBUG
1373 pDispContext->cCmds = 0;
1374#endif
1375 VBoxVideoCmnSpinLockRelease(PrimaryExtension, &pDispContext->pSynchLock, oldIrql);
1376
1377 DBG_CHECKLIST(PrimaryExtension, pDispContext, NULL);
1378
1379 return VINF_SUCCESS;
1380 }
1381 }
1382
1383 return VERR_INVALID_PARAMETER;
1384}
1385
1386static DECLCALLBACK(int) vboxVBVAChannelGenericHandler(void *pvHandler, uint16_t u16ChannelInfo, void *pvBuffer, HGSMISIZE cbBuffer)
1387{
1388 VBVA_CHANNELCONTEXTS *pCallbacks = (VBVA_CHANNELCONTEXTS*)pvHandler;
1389// Assert(0);
1390 Assert(cbBuffer > VBVAHOSTCMD_HDRSIZE);
1391 if(cbBuffer > VBVAHOSTCMD_HDRSIZE)
1392 {
1393 VBVAHOSTCMD *pHdr = (VBVAHOSTCMD*)pvBuffer;
1394 Assert(pHdr->iDstID >= 0);
1395 if(pHdr->iDstID >= 0)
1396 {
1397 VBVADISP_CHANNELCONTEXT* pHandler = vboxVBVAFindHandlerInfo(pCallbacks, pHdr->iDstID);
1398 Assert(pHandler && pHandler->bValid);
1399 if(pHandler && pHandler->bValid)
1400 {
1401 VBVAHOSTCMD *pFirst = NULL, *pLast = NULL;
1402 for(VBVAHOSTCMD *pCur = pHdr; pCur; )
1403 {
1404 Assert(!pCur->u.Data);
1405 Assert(!pFirst);
1406 Assert(!pLast);
1407
1408 switch(u16ChannelInfo)
1409 {
1410 case VBVAHG_DISPLAY_CUSTOM:
1411 {
1412 if(pLast)
1413 {
1414 pLast->u.pNext = pCur;
1415 pLast = pCur;
1416 }
1417 else
1418 {
1419 pFirst = pCur;
1420 pLast = pCur;
1421 }
1422 Assert(!pCur->u.Data);
1423 //TODO: use offset here
1424 pCur = pCur->u.pNext;
1425 Assert(!pCur);
1426 Assert(pFirst);
1427 Assert(pFirst == pLast);
1428 break;
1429 }
1430 case VBVAHG_EVENT:
1431 {
1432 VBVAHOSTCMDEVENT *pEventCmd = VBVAHOSTCMD_BODY(pCur, VBVAHOSTCMDEVENT);
1433#ifndef VBOX_WITH_WDDM
1434 PEVENT pEvent = (PEVENT)pEventCmd->pEvent;
1435 pCallbacks->PrimaryExtension->u.primary.VideoPortProcs.pfnSetEvent(
1436 pCallbacks->PrimaryExtension,
1437 pEvent);
1438#else
1439 PKEVENT pEvent = (PKEVENT)pEventCmd->pEvent;
1440 KeSetEvent(pEvent, 0, FALSE);
1441#endif
1442 }
1443 default:
1444 {
1445 DBG_CHECKLIST(pCallbacks->PrimaryExtension, pHandler, pCur);
1446 Assert(u16ChannelInfo==VBVAHG_EVENT);
1447 Assert(!pCur->u.Data);
1448 //TODO: use offset here
1449 if(pLast)
1450 pLast->u.pNext = pCur->u.pNext;
1451 VBVAHOSTCMD * pNext = pCur->u.pNext;
1452 pCur->u.pNext = NULL;
1453 HGSMIHostCmdComplete(commonFromDeviceExt(pCallbacks->PrimaryExtension), pCur);
1454 pCur = pNext;
1455 Assert(!pCur);
1456 Assert(!pFirst);
1457 Assert(pFirst == pLast);
1458 break;
1459 }
1460 }
1461 }
1462
1463 DBG_CHECKLIST(pCallbacks->PrimaryExtension, pHandler, pFirst);
1464
1465 /* we do not support lists currently */
1466 Assert(pFirst == pLast);
1467 if(pLast)
1468 {
1469 Assert(pLast->u.pNext == NULL);
1470 }
1471
1472 if(pFirst)
1473 {
1474 Assert(pLast);
1475 UCHAR oldIrql;
1476 VBoxVideoCmnSpinLockAcquire(pCallbacks->PrimaryExtension,
1477 &pHandler->pSynchLock,
1478 &oldIrql);
1479
1480 DBG_CHECKLIST_LOCKED(pHandler, pFirst);
1481
1482 if(pHandler->pLastCmd)
1483 {
1484 pHandler->pLastCmd->u.pNext = pFirst;
1485 Assert(pHandler->pFirstCmd);
1486 }
1487 else
1488 {
1489 Assert(!pHandler->pFirstCmd);
1490 pHandler->pFirstCmd = pFirst;
1491 }
1492 pHandler->pLastCmd = pLast;
1493#ifdef DEBUG
1494 pHandler->cCmds++;
1495#endif
1496 DBG_CHECKLIST_LOCKED(pHandler, NULL);
1497
1498 VBoxVideoCmnSpinLockRelease(pCallbacks->PrimaryExtension,
1499 &pHandler->pSynchLock,
1500 oldIrql);
1501 }
1502 else
1503 {
1504 Assert(!pLast);
1505 }
1506 return VINF_SUCCESS;
1507 }
1508 }
1509 else
1510 {
1511 //TODO: impl
1512// HGSMIMINIPORT_CHANNELCONTEXT *pHandler = vboxVideoHGSMIFindHandler;
1513// if(pHandler && pHandler->pfnChannelHandler)
1514// {
1515// pHandler->pfnChannelHandler(pHandler->pvChannelHandler, u16ChannelInfo, pHdr, cbBuffer);
1516//
1517// return VINF_SUCCESS;
1518// }
1519 }
1520 }
1521 /* no handlers were found, need to complete the command here */
1522 HGSMIHostCmdComplete(commonFromDeviceExt(pCallbacks->PrimaryExtension), pvBuffer);
1523 return VINF_SUCCESS;
1524}
1525
1526static HGSMICHANNELHANDLER g_OldHandler;
1527
1528int vboxVBVAChannelDisplayEnable(PDEVICE_EXTENSION PrimaryExtension,
1529 int iDisplay, /* negative would mean this is a miniport handler */
1530 uint8_t u8Channel)
1531{
1532 VBVA_CHANNELCONTEXTS * pContexts;
1533 HGSMICHANNEL * pChannel = HGSMIChannelFindById (&commonFromDeviceExt(PrimaryExtension)->channels, u8Channel);
1534 if(!pChannel)
1535 {
1536 int rc = vboxVBVACreateChannelContexts(PrimaryExtension, &pContexts);
1537 if(RT_FAILURE(rc))
1538 {
1539 return rc;
1540 }
1541 }
1542 else
1543 {
1544 pContexts = (VBVA_CHANNELCONTEXTS *)pChannel->handler.pvHandler;
1545 }
1546
1547 VBVADISP_CHANNELCONTEXT *pDispContext = vboxVBVAFindHandlerInfo(pContexts, iDisplay);
1548 Assert(pDispContext);
1549 if(pDispContext)
1550 {
1551#ifdef DEBUGVHWASTRICT
1552 Assert(!pDispContext->bValid);
1553#endif
1554 Assert(!pDispContext->pFirstCmd);
1555 Assert(!pDispContext->pLastCmd);
1556 if(!pDispContext->bValid)
1557 {
1558 pDispContext->bValid = true;
1559 pDispContext->pFirstCmd = NULL;
1560 pDispContext->pLastCmd= NULL;
1561#ifdef DEBUG
1562 pDispContext->cCmds = 0;
1563#endif
1564
1565 VBoxVideoCmnSpinLockCreate(PrimaryExtension, &pDispContext->pSynchLock);
1566
1567 int rc = VINF_SUCCESS;
1568 if(!pChannel)
1569 {
1570 rc = HGSMIChannelRegister (&commonFromDeviceExt(PrimaryExtension)->channels,
1571 u8Channel,
1572 "VGA Miniport HGSMI channel",
1573 vboxVBVAChannelGenericHandler,
1574 pContexts,
1575 &g_OldHandler);
1576 }
1577
1578 if(RT_SUCCESS(rc))
1579 {
1580 pContexts->cUsed++;
1581 return VINF_SUCCESS;
1582 }
1583 }
1584 }
1585
1586 if(!pChannel)
1587 {
1588 vboxVBVADeleteChannelContexts(PrimaryExtension, pContexts);
1589 }
1590
1591 return VERR_GENERAL_FAILURE;
1592}
1593#endif /* !VBOX_WITH_WDDM */
1594
1595/** @todo Mouse pointer position to be read from VMMDev memory, address of the memory region
1596 * can be queried from VMMDev via an IOCTL. This VMMDev memory region will contain
1597 * host information which is needed by the guest.
1598 *
1599 * Reading will not cause a switch to the host.
1600 *
1601 * Have to take into account:
1602 * * synchronization: host must write to the memory only from EMT,
1603 * large structures must be read under flag, which tells the host
1604 * that the guest is currently reading the memory (OWNER flag?).
1605 * * guest writes: may be allocate a page for the host info and make
1606 * the page readonly for the guest.
1607 * * the information should be available only for additions drivers.
1608 * * VMMDev additions driver will inform the host which version of the info it expects,
1609 * host must support all versions.
1610 *
1611 */
1612
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette