VirtualBox

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

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

wddm: more correct visible VRAM size reporting + some cleaning

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

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