VirtualBox

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

Last change on this file since 29625 was 28800, checked in by vboxsync, 15 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

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