VirtualBox

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

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

wddm: more guest autoresize impl

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 51.2 KB
Line 
1/* $Id: VBoxVideoHGSMI.cpp 27997 2010-04-06 10:01:47Z 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 /* use 25% od VRAM for DMA command buffer
937 * @todo: ^^^? */
938 ULONG ulSize = ulAvailable / 4;
939
940 /* Align down to 4096 bytes. */
941 ulSize &= ~0xFFF;
942 ULONG offset = ulAvailable - ulSize;
943
944 Assert(!(offset & 0xFFF));
945
946 rc = vboxVdmaCreate (PrimaryExtension, &PrimaryExtension->u.primary.Vdma, offset, ulSize);
947 AssertRC(rc);
948 if (RT_SUCCESS(rc))
949 {
950 /* can enable it right away since the host does not need any screen/FB info
951 * for basic DMA functionality */
952 rc = vboxVdmaEnable(PrimaryExtension, &PrimaryExtension->u.primary.Vdma);
953 AssertRC(rc);
954 if (RT_FAILURE(rc))
955 vboxVdmaDestroy(PrimaryExtension, &PrimaryExtension->u.primary.Vdma);
956 }
957
958 if (RT_FAILURE(rc))
959 PrimaryExtension->u.primary.bHGSMI = FALSE;
960 }
961#endif
962
963 if (!PrimaryExtension->u.primary.bHGSMI)
964 {
965 /* Unmap the memory if VBoxVideo is not supported. */
966 VBoxUnmapAdapterMemory (PrimaryExtension, &PrimaryExtension->u.primary.pvMiniportHeap, PrimaryExtension->u.primary.cbMiniportHeap);
967 VBoxUnmapAdapterMemory (PrimaryExtension, &PrimaryExtension->u.primary.pvAdapterInformation, VBVA_ADAPTER_INFORMATION_SIZE);
968
969 HGSMIHeapDestroy (&PrimaryExtension->u.primary.hgsmiAdapterHeap);
970 }
971
972 if (PrimaryExtension->u.primary.bHGSMI)
973 {
974 VBoxVideoCmnSpinLockCreate(PrimaryExtension, &PrimaryExtension->u.primary.pSynchLock);
975 }
976
977 dprintf(("VBoxVideo::VBoxSetupDisplays: finished\n"));
978}
979
980
981/*
982 * Send the pointer shape to the host.
983 */
984typedef struct _MOUSEPOINTERSHAPECTX
985{
986 VIDEO_POINTER_ATTRIBUTES *pPointerAttr;
987 uint32_t cbData;
988 int32_t i32Result;
989} MOUSEPOINTERSHAPECTX;
990
991static int vbvaInitMousePointerShape (PDEVICE_EXTENSION PrimaryExtension, void *pvContext, void *pvData)
992{
993 NOREF (PrimaryExtension);
994
995 MOUSEPOINTERSHAPECTX *pCtx = (MOUSEPOINTERSHAPECTX *)pvContext;
996 VBVAMOUSEPOINTERSHAPE *p = (VBVAMOUSEPOINTERSHAPE *)pvData;
997
998 /* Will be updated by the host. */
999 p->i32Result = VINF_SUCCESS;
1000
1001 /* We have our custom flags in the field */
1002 p->fu32Flags = pCtx->pPointerAttr->Enable & 0x0000FFFF;
1003
1004 p->u32HotX = (pCtx->pPointerAttr->Enable >> 16) & 0xFF;
1005 p->u32HotY = (pCtx->pPointerAttr->Enable >> 24) & 0xFF;
1006 p->u32Width = pCtx->pPointerAttr->Width;
1007 p->u32Height = pCtx->pPointerAttr->Height;
1008
1009 if (p->fu32Flags & VBOX_MOUSE_POINTER_SHAPE)
1010 {
1011 /* If shape is supplied, then alway create the pointer visible.
1012 * See comments in 'vboxUpdatePointerShape'
1013 */
1014 p->fu32Flags |= VBOX_MOUSE_POINTER_VISIBLE;
1015
1016 /* Copy the actual pointer data. */
1017 memcpy (p->au8Data, pCtx->pPointerAttr->Pixels, pCtx->cbData);
1018 }
1019
1020 return VINF_SUCCESS;
1021}
1022
1023static int vbvaFinalizeMousePointerShape (PDEVICE_EXTENSION PrimaryExtension, void *pvContext, void *pvData)
1024{
1025 NOREF (PrimaryExtension);
1026
1027 MOUSEPOINTERSHAPECTX *pCtx = (MOUSEPOINTERSHAPECTX *)pvContext;
1028 VBVAMOUSEPOINTERSHAPE *p = (VBVAMOUSEPOINTERSHAPE *)pvData;
1029
1030 pCtx->i32Result = p->i32Result;
1031
1032 return VINF_SUCCESS;
1033}
1034
1035BOOLEAN vboxUpdatePointerShape (PDEVICE_EXTENSION DeviceExtension,
1036 PVIDEO_POINTER_ATTRIBUTES pointerAttr,
1037 uint32_t cbLength)
1038{
1039#ifndef VBOXWDDM
1040 PDEVICE_EXTENSION PrimaryExtension = DeviceExtension->pPrimary;
1041
1042 /* In multimonitor case the HW mouse pointer is the same on all screens,
1043 * and Windows calls each display driver with the same pointer data: visible for
1044 * the screen where the pointer is and invisible for other screens.
1045 *
1046 * This driver passes the shape to the host only from primary screen and makes
1047 * the pointer always visible (in vbvaInitMousePointerShape).
1048 *
1049 * The simple solution makes it impossible to create the shape and keep the mouse
1050 * pointer invisible. New shapes will be created visible.
1051 * But:
1052 * 1) VBox frontends actually ignore the visibility flag if VBOX_MOUSE_POINTER_SHAPE
1053 * is set and always create new pointers visible.
1054 * 2) Windows uses DrvMovePointer to hide the pointer, which will still work.
1055 */
1056
1057 if (DeviceExtension->iDevice != PrimaryExtension->iDevice)
1058 {
1059 dprintf(("vboxUpdatePointerShape: ignore non primary device %d(%d)\n",
1060 DeviceExtension->iDevice, PrimaryExtension->iDevice));
1061 /* Success. */
1062 return TRUE;
1063 }
1064#else
1065 PDEVICE_EXTENSION PrimaryExtension = DeviceExtension;
1066#endif
1067
1068 uint32_t cbData = 0;
1069
1070 if (pointerAttr->Enable & VBOX_MOUSE_POINTER_SHAPE)
1071 {
1072 /* Size of the pointer data: sizeof (AND mask) + sizeof (XOR_MASK) */
1073 cbData = ((((pointerAttr->Width + 7) / 8) * pointerAttr->Height + 3) & ~3)
1074 + pointerAttr->Width * 4 * pointerAttr->Height;
1075 }
1076
1077#ifndef DEBUG_misha
1078 dprintf(("vboxUpdatePointerShape: cbData %d, %dx%d\n",
1079 cbData, pointerAttr->Width, pointerAttr->Height));
1080#endif
1081
1082 if (cbData > cbLength - sizeof(VIDEO_POINTER_ATTRIBUTES))
1083 {
1084 dprintf(("vboxUpdatePointerShape: calculated pointer data size is too big (%d bytes, limit %d)\n",
1085 cbData, cbLength - sizeof(VIDEO_POINTER_ATTRIBUTES)));
1086 return FALSE;
1087 }
1088
1089 MOUSEPOINTERSHAPECTX ctx;
1090
1091 ctx.pPointerAttr = pointerAttr;
1092 ctx.cbData = cbData;
1093 ctx.i32Result = VERR_NOT_SUPPORTED;
1094
1095 int rc = vboxCallVBVA (PrimaryExtension,
1096 VBVA_MOUSE_POINTER_SHAPE,
1097 sizeof (VBVAMOUSEPOINTERSHAPE) + cbData,
1098 vbvaInitMousePointerShape,
1099 vbvaFinalizeMousePointerShape,
1100 &ctx);
1101#ifndef DEBUG_misha
1102 dprintf(("VBoxVideo::vboxMousePointerShape: rc %d, i32Result = %d\n", rc, ctx.i32Result));
1103#endif
1104
1105 return RT_SUCCESS(rc) && RT_SUCCESS(ctx.i32Result);
1106}
1107
1108typedef struct _VBVAMINIPORT_CHANNELCONTEXT
1109{
1110 PFNHGSMICHANNELHANDLER pfnChannelHandler;
1111 void *pvChannelHandler;
1112}VBVAMINIPORT_CHANNELCONTEXT;
1113
1114typedef struct _VBVADISP_CHANNELCONTEXT
1115{
1116 struct _VBVAHOSTCMD * pFirstCmd;
1117 struct _VBVAHOSTCMD * pLastCmd;
1118 VBOXVCMNSPIN_LOCK pSynchLock;
1119#ifdef DEBUG
1120 int cCmds;
1121#endif
1122 bool bValid;
1123}VBVADISP_CHANNELCONTEXT;
1124
1125#ifdef DEBUG
1126void dbgCheckListLocked(const VBVADISP_CHANNELCONTEXT *pList, struct _VBVAHOSTCMD * pCmd)
1127{
1128 int counter = 0;
1129 for(struct _VBVAHOSTCMD * pCur = pList->pFirstCmd; pCur; pCur=pCur->u.pNext)
1130 {
1131 Assert(pCur != pCmd);
1132 if(pCur == pList->pLastCmd)
1133 {
1134 Assert(pCur->u.pNext == NULL);
1135 }
1136 if(pCur->u.pNext == NULL)
1137 {
1138 Assert(pCur == pList->pLastCmd);
1139 }
1140 counter++;
1141 }
1142
1143 Assert(counter == pList->cCmds);
1144}
1145
1146void dbgCheckList(PDEVICE_EXTENSION PrimaryExtension, VBVADISP_CHANNELCONTEXT *pList, struct _VBVAHOSTCMD * pCmd)
1147{
1148 VBOXVCMNIRQL oldIrql;
1149 VBoxVideoCmnSpinLockAcquire(PrimaryExtension, &pList->pSynchLock, &oldIrql);
1150
1151 dbgCheckListLocked(pList, pCmd);
1152
1153 VBoxVideoCmnSpinLockRelease(PrimaryExtension, &pList->pSynchLock, oldIrql);
1154}
1155
1156#define DBG_CHECKLIST_LOCKED(_pl, pc) dbgCheckListLocked(_pl, pc)
1157#define DBG_CHECKLIST(_pe, _pl, pc) dbgCheckList(_pe, _pl, pc)
1158
1159#else
1160#define DBG_CHECKLIST_LOCKED(_pl, pc) do{}while(0)
1161#define DBG_CHECKLIST(_pe, _pl, pc) do{}while(0)
1162#endif
1163
1164
1165typedef struct _VBVA_CHANNELCONTEXTS
1166{
1167 PDEVICE_EXTENSION PrimaryExtension;
1168 uint32_t cUsed;
1169 uint32_t cContexts;
1170 VBVAMINIPORT_CHANNELCONTEXT mpContext;
1171 VBVADISP_CHANNELCONTEXT aContexts[1];
1172}VBVA_CHANNELCONTEXTS;
1173
1174static int vboxVBVADeleteChannelContexts(PDEVICE_EXTENSION PrimaryExtension, VBVA_CHANNELCONTEXTS * pContext)
1175{
1176 VBoxVideoCmnMemFree(PrimaryExtension,pContext);
1177 return VINF_SUCCESS;
1178}
1179
1180static int vboxVBVACreateChannelContexts(PDEVICE_EXTENSION PrimaryExtension, VBVA_CHANNELCONTEXTS ** ppContext)
1181{
1182#ifndef VBOXWDDM
1183 uint32_t cDisplays = (uint32_t)PrimaryExtension->u.primary.cDisplays;
1184#else
1185 uint32_t cDisplays = (uint32_t)PrimaryExtension->cSources;
1186#endif
1187 const size_t size = RT_OFFSETOF(VBVA_CHANNELCONTEXTS, aContexts[cDisplays]);
1188 VBVA_CHANNELCONTEXTS * pContext = (VBVA_CHANNELCONTEXTS*)VBoxVideoCmnMemAllocNonPaged(PrimaryExtension, size, MEM_TAG);
1189 if(pContext)
1190 {
1191 memset(pContext, 0, size);
1192 pContext->cContexts = cDisplays;
1193 pContext->PrimaryExtension = PrimaryExtension;
1194 *ppContext = pContext;
1195 return VINF_SUCCESS;
1196 }
1197 return VERR_GENERAL_FAILURE;
1198}
1199
1200static VBVADISP_CHANNELCONTEXT* vboxVBVAFindHandlerInfo(VBVA_CHANNELCONTEXTS *pCallbacks, int iId)
1201{
1202 if(iId < 0)
1203 {
1204 return NULL;
1205 }
1206 else if(pCallbacks->cContexts > (uint32_t)iId)
1207 {
1208 return &pCallbacks->aContexts[iId];
1209 }
1210 return NULL;
1211}
1212
1213#ifndef VBOXWDDM
1214DECLCALLBACK(void) hgsmiHostCmdComplete (HVBOXVIDEOHGSMI hHGSMI, struct _VBVAHOSTCMD * pCmd)
1215{
1216 PDEVICE_EXTENSION PrimaryExtension = ((PDEVICE_EXTENSION)hHGSMI)->pPrimary;
1217 HGSMIHostCmdComplete (PrimaryExtension, pCmd);
1218}
1219
1220DECLCALLBACK(int) hgsmiHostCmdRequest (HVBOXVIDEOHGSMI hHGSMI, uint8_t u8Channel, struct _VBVAHOSTCMD ** ppCmd)
1221{
1222// if(display < 0)
1223// return VERR_INVALID_PARAMETER;
1224 if(!ppCmd)
1225 return VERR_INVALID_PARAMETER;
1226
1227 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)hHGSMI;
1228 PDEVICE_EXTENSION PrimaryExtension = pDevExt->pPrimary;
1229
1230 /* pick up the host commands */
1231 VBoxVideoHGSMIDpc(PrimaryExtension, NULL);
1232
1233 HGSMICHANNEL * pChannel = HGSMIChannelFindById (&PrimaryExtension->u.primary.channels, u8Channel);
1234 if(pChannel)
1235 {
1236 VBVA_CHANNELCONTEXTS * pContexts = (VBVA_CHANNELCONTEXTS *)pChannel->handler.pvHandler;
1237 VBVADISP_CHANNELCONTEXT *pDispContext = vboxVBVAFindHandlerInfo(pContexts, pDevExt->iDevice);
1238 Assert(pDispContext);
1239 if(pDispContext)
1240 {
1241 UCHAR oldIrql;
1242 VBoxVideoCmnSpinLockAcquire(PrimaryExtension, &pDispContext->pSynchLock, &oldIrql);
1243
1244 DBG_CHECKLIST_LOCKED(pDispContext, NULL);
1245
1246 *ppCmd = pDispContext->pFirstCmd;
1247 pDispContext->pFirstCmd = NULL;
1248 pDispContext->pLastCmd = NULL;
1249#ifdef DEBUG
1250 pDispContext->cCmds = 0;
1251#endif
1252 VBoxVideoCmnSpinLockRelease(PrimaryExtension, &pDispContext->pSynchLock, oldIrql);
1253
1254 DBG_CHECKLIST(PrimaryExtension, pDispContext, NULL);
1255
1256 return VINF_SUCCESS;
1257 }
1258 }
1259
1260 return VERR_INVALID_PARAMETER;
1261}
1262#endif
1263
1264static DECLCALLBACK(int) vboxVBVAChannelGenericHandler(void *pvHandler, uint16_t u16ChannelInfo, void *pvBuffer, HGSMISIZE cbBuffer)
1265{
1266 VBVA_CHANNELCONTEXTS *pCallbacks = (VBVA_CHANNELCONTEXTS*)pvHandler;
1267// Assert(0);
1268 Assert(cbBuffer > VBVAHOSTCMD_HDRSIZE);
1269 if(cbBuffer > VBVAHOSTCMD_HDRSIZE)
1270 {
1271 VBVAHOSTCMD *pHdr = (VBVAHOSTCMD*)pvBuffer;
1272 Assert(pHdr->iDstID >= 0);
1273 if(pHdr->iDstID >= 0)
1274 {
1275 VBVADISP_CHANNELCONTEXT* pHandler = vboxVBVAFindHandlerInfo(pCallbacks, pHdr->iDstID);
1276 Assert(pHandler && pHandler->bValid);
1277 if(pHandler && pHandler->bValid)
1278 {
1279 VBVAHOSTCMD *pFirst = NULL, *pLast = NULL;
1280 for(VBVAHOSTCMD *pCur = pHdr; pCur; )
1281 {
1282 Assert(!pCur->u.Data);
1283 Assert(!pFirst);
1284 Assert(!pLast);
1285
1286 switch(u16ChannelInfo)
1287 {
1288 case VBVAHG_DISPLAY_CUSTOM:
1289 {
1290 if(pLast)
1291 {
1292 pLast->u.pNext = pCur;
1293 pLast = pCur;
1294 }
1295 else
1296 {
1297 pFirst = pCur;
1298 pLast = pCur;
1299 }
1300 Assert(!pCur->u.Data);
1301 //TODO: use offset here
1302 pCur = pCur->u.pNext;
1303 Assert(!pCur);
1304 Assert(pFirst);
1305 Assert(pFirst == pLast);
1306 break;
1307 }
1308 case VBVAHG_EVENT:
1309 {
1310 VBVAHOSTCMDEVENT *pEventCmd = VBVAHOSTCMD_BODY(pCur, VBVAHOSTCMDEVENT);
1311#ifndef VBOXWDDM
1312 PEVENT pEvent = (PEVENT)pEventCmd->pEvent;
1313 pCallbacks->PrimaryExtension->u.primary.VideoPortProcs.pfnSetEvent(
1314 pCallbacks->PrimaryExtension,
1315 pEvent);
1316#else
1317 PKEVENT pEvent = (PKEVENT)pEventCmd->pEvent;
1318 KeSetEvent(pEvent, 0, FALSE);
1319#endif
1320 }
1321 default:
1322 {
1323 DBG_CHECKLIST(pCallbacks->PrimaryExtension, pHandler, pCur);
1324 Assert(u16ChannelInfo==VBVAHG_EVENT);
1325 Assert(!pCur->u.Data);
1326 //TODO: use offset here
1327 if(pLast)
1328 pLast->u.pNext = pCur->u.pNext;
1329 VBVAHOSTCMD * pNext = pCur->u.pNext;
1330 pCur->u.pNext = NULL;
1331 HGSMIHostCmdComplete(pCallbacks->PrimaryExtension, pCur);
1332 pCur = pNext;
1333 Assert(!pCur);
1334 Assert(!pFirst);
1335 Assert(pFirst == pLast);
1336 break;
1337 }
1338 }
1339 }
1340
1341 DBG_CHECKLIST(pCallbacks->PrimaryExtension, pHandler, pFirst);
1342
1343 /* we do not support lists currently */
1344 Assert(pFirst == pLast);
1345 if(pLast)
1346 {
1347 Assert(pLast->u.pNext == NULL);
1348 }
1349
1350 if(pFirst)
1351 {
1352 Assert(pLast);
1353 UCHAR oldIrql;
1354 VBoxVideoCmnSpinLockAcquire(pCallbacks->PrimaryExtension,
1355 &pHandler->pSynchLock,
1356 &oldIrql);
1357
1358 DBG_CHECKLIST_LOCKED(pHandler, pFirst);
1359
1360 if(pHandler->pLastCmd)
1361 {
1362 pHandler->pLastCmd->u.pNext = pFirst;
1363 Assert(pHandler->pFirstCmd);
1364 }
1365 else
1366 {
1367 Assert(!pHandler->pFirstCmd);
1368 pHandler->pFirstCmd = pFirst;
1369 }
1370 pHandler->pLastCmd = pLast;
1371#ifdef DEBUG
1372 pHandler->cCmds++;
1373#endif
1374 DBG_CHECKLIST_LOCKED(pHandler, NULL);
1375
1376 VBoxVideoCmnSpinLockRelease(pCallbacks->PrimaryExtension,
1377 &pHandler->pSynchLock,
1378 oldIrql);
1379 }
1380 else
1381 {
1382 Assert(!pLast);
1383 }
1384 return VINF_SUCCESS;
1385 }
1386 }
1387 else
1388 {
1389 //TODO: impl
1390// HGSMIMINIPORT_CHANNELCONTEXT *pHandler = vboxVideoHGSMIFindHandler;
1391// if(pHandler && pHandler->pfnChannelHandler)
1392// {
1393// pHandler->pfnChannelHandler(pHandler->pvChannelHandler, u16ChannelInfo, pHdr, cbBuffer);
1394//
1395// return VINF_SUCCESS;
1396// }
1397 }
1398 }
1399 /* no handlers were found, need to complete the command here */
1400 HGSMIHostCmdComplete(pCallbacks->PrimaryExtension, pvBuffer);
1401 return VINF_SUCCESS;
1402}
1403
1404static HGSMICHANNELHANDLER g_OldHandler;
1405
1406int vboxVBVAChannelDisplayEnable(PDEVICE_EXTENSION PrimaryExtension,
1407 int iDisplay, /* negative would mean this is a miniport handler */
1408 uint8_t u8Channel)
1409{
1410 VBVA_CHANNELCONTEXTS * pContexts;
1411 HGSMICHANNEL * pChannel = HGSMIChannelFindById (&PrimaryExtension->u.primary.channels, u8Channel);
1412 if(!pChannel)
1413 {
1414 int rc = vboxVBVACreateChannelContexts(PrimaryExtension, &pContexts);
1415 if(RT_FAILURE(rc))
1416 {
1417 return rc;
1418 }
1419 }
1420 else
1421 {
1422 pContexts = (VBVA_CHANNELCONTEXTS *)pChannel->handler.pvHandler;
1423 }
1424
1425 VBVADISP_CHANNELCONTEXT *pDispContext = vboxVBVAFindHandlerInfo(pContexts, iDisplay);
1426 Assert(pDispContext);
1427 if(pDispContext)
1428 {
1429#ifdef DEBUGVHWASTRICT
1430 Assert(!pDispContext->bValid);
1431#endif
1432 Assert(!pDispContext->pFirstCmd);
1433 Assert(!pDispContext->pLastCmd);
1434 if(!pDispContext->bValid)
1435 {
1436 pDispContext->bValid = true;
1437 pDispContext->pFirstCmd = NULL;
1438 pDispContext->pLastCmd= NULL;
1439#ifdef DEBUG
1440 pDispContext->cCmds = 0;
1441#endif
1442
1443 VBoxVideoCmnSpinLockCreate(PrimaryExtension, &pDispContext->pSynchLock);
1444
1445 int rc = VINF_SUCCESS;
1446 if(!pChannel)
1447 {
1448 rc = HGSMIChannelRegister (&PrimaryExtension->u.primary.channels,
1449 u8Channel,
1450 "VGA Miniport HGSMI channel",
1451 vboxVBVAChannelGenericHandler,
1452 pContexts,
1453 &g_OldHandler);
1454 }
1455
1456 if(RT_SUCCESS(rc))
1457 {
1458 pContexts->cUsed++;
1459 return VINF_SUCCESS;
1460 }
1461 }
1462 }
1463
1464 if(!pChannel)
1465 {
1466 vboxVBVADeleteChannelContexts(PrimaryExtension, pContexts);
1467 }
1468
1469 return VERR_GENERAL_FAILURE;
1470}
1471
1472/** @todo Mouse pointer position to be read from VMMDev memory, address of the memory region
1473 * can be queried from VMMDev via an IOCTL. This VMMDev memory region will contain
1474 * host information which is needed by the guest.
1475 *
1476 * Reading will not cause a switch to the host.
1477 *
1478 * Have to take into account:
1479 * * synchronization: host must write to the memory only from EMT,
1480 * large structures must be read under flag, which tells the host
1481 * that the guest is currently reading the memory (OWNER flag?).
1482 * * guest writes: may be allocate a page for the host info and make
1483 * the page readonly for the guest.
1484 * * the information should be available only for additions drivers.
1485 * * VMMDev additions driver will inform the host which version of the info it expects,
1486 * host must support all versions.
1487 *
1488 */
1489
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